我想要做的是将文件(使用Apache poi的excel文件)中的键/值对加载到将用作查找表的静态映射中。一旦加载,表格就不会改变。
public final class LookupTable
{
private final static Map<String, String> map;
static {
map = new HashMap<String, String>();
// should do initialization here
// InputStream is = new FileInputStream(new File("pathToFile"));
// not sure how to pass pathToFile without hardcoding it?
}
private LookupTable() {
}
public static void loadTable(InputStream is) {
// read table from file
// load it into map
map.put("regex", "value");
}
public static String getValue(String key) {
return map.get(key);
}
}
理想情况下,我想在静态初始化块中加载地图,但是如何在没有硬编码的情况下传递流?我在使用loadTable静态方法时看到的问题是在调用其他静态方法之前可能没有调用它。
// LookupTable.loadTable(stream);
LookupTable.getValue("regex"); // null since map was never populated.
有更好的方法吗?
答案 0 :(得分:3)
您使用的任何内容都必须在启动时可访问。据我所知,您的选择是:
static
方法进行搜索。System.getProperty("filename", "/default/filename")
。更好,因为它至少可以使用环境或JVM启动时的-D
参数进行自定义。ClassLoader
getResource*
方法。这可能是正确答案。具体来说,您可能希望在当前线程的上下文ClassLoader
getResourceAsStream()
上使用Thread.currentThread().getContextClassLoader()
方法。 (所以,总共Thread.currentThread().getContextClassLoader().getResourceAsStream("filename")
。)然后ClassLoader
将为您找到您的资源(只要您将其放在CLASSPATH
中的某个地方。)答案 1 :(得分:2)
是的,有一种更好的方法,在必须使用之前使用Factory设计模式初始化对象:
答案 2 :(得分:1)
您无法将信息传递到静态初始化块 - 它们应该独立工作。由于您计划通过的流需要在程序开始执行之前知道,因此大概您的LookupTable
也应该能够找到它。例如,这可能是某种为您提供流的配置实用程序。然后你可以像这样编写初始化器:
static {
InputStream exelStream = MyConfigUtil.getExcelStreamForLookup();
loadTable(exelStream);
}
据推测,系统中有一个类可以从已知的源中获取Excel流。源不需要硬编码:它可以从配置文件中读取位置,或从服务器上的预定义网络位置接收数据。在所有情况下,获取Excel流的过程必须在某处“触底”,因为系统中的某些东西需要能够在没有其他参数的情况下找到它。
答案 3 :(得分:0)
这可能是使用延迟加载地图的情况。
但是,您需要在第一次调用inputFileName
之前设置getValue()
。这将在您的应用程序的初始化代码中完成。 (或者您可以使用静态方法进行设置。)
这指出了延迟加载的优势。在第一次调用getValue()
之前,您不必拥有文件名。使用静态初始化程序,您必须将文件名存储在类之外的某处,以便在类加载时(但在静态字段初始化之后)用于加载数据。
public static String inputFileName = null;
public static String getValue(String key) {
if (map == null) {
map = = new HashMap<String, String>();
// open the file using 'inputFileName'
loadTable(InputStream is);
}
return map.get(key);
}
如果你的代码是多线程的,请告诉我,我会评论同步问题。
<强>交替强>
您也可以使用Spring注入地图并在其他类中构建它 - 例如MapBuilder
。
答案 4 :(得分:0)
尝试使用System.getProperty()并在命令行中使用-D传递参数。
static String prop;
static {
prop = System.getProperty("java.home");
}
public static void main(String... args) {
System.out.println(prop);
}
答案 5 :(得分:0)
这不是直接回答你的问题,但我不明白为什么map
必须是静态的。您可以将map
更改为非静态,并将构造函数更改为public LookupTable(File file) {...fill map...}
。如果你有不同的excel文件,你甚至可以拥有该类的许多实例;它现在可能不是这样,但它将“面向未来”代码。
答案 6 :(得分:0)
如果适合您的情况,我会建议singleton enum approach。
public enum LookupTable {
INSTANCE(FileManager.getFileName());
LookupTable(String fileName){
props = new HashMap<String,String>();
//Read from excel and fill the hashmap
}
private final Map<String, String> props;
public String getMapValue(String key){
return props.get(key);
}
}
可以通过
调用LookupTable.INSTANCE.getMapValue("mykey");
这将按顺序调用这些方法
后续调用LookupTable.INSTANCE.getMapValue(“mysecondkey”)将仅在事先初始化INSTANCE时调用getMapValue。