我正在开发一个小项目,一个Web应用程序,我根据用户文本输入对数据进行一些分析。
为此,我需要使用一张地图,其中我有单词和相应的分数。
这就是我的尝试:
public class EnDict {
private static Map<String, Integer> map = new HashMap<String, Integer>() {
{
put("abandon", -2);
put("ability", 2);
put("abuse", -3);
//and so on, thousands of pairs
}
}
}
它有效,但这样我需要在我的班级中对键/值对进行硬编码。所以,如果我想添加更多对,我必须编写代码,而不是只添加对执行文本文件。看起来不太好。
所以我想从文本文件中获取这些对。此外,我需要在应用程序启动时创建此Map,因此当任何用户发出请求时,Map已经加载,并且可以由分析逻辑使用。我的意思是,Map必须在第一个请求发生之前在内存中,并在之后的内存中,在后续请求中使用。它需要在我的应用程序的任何地方都可见(也许这部分不是很清楚,但我不知道如何更好地解释它。)
我已经尝试了一些研究,但是从应用程序启动以来,没有找到将Map保留在内存中的这一特定部分的答案。它类似于Application_Start
类中的ASP.NET Global
方法。
我非常喜欢编程,特别是Java,所以也许我完全被误导了如何才能成为完成这项任务的最佳方式。如果是这种情况,我们将不胜感激。
我正在使用Servlets,JSP和Tomcat。
编辑: 实际上,它不只是一张地图。将有几个地图,这些地图可以有一些相同的键。
答案 0 :(得分:3)
将此地图定义为静态 - 它将在内存中,直到加载此类的类加载器不被垃圾回收。
我在上面提到:http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.7
静态成员链接到类,并且上面的规范说明在类加载器到位之前不会卸载类。
而对象确实会收集垃圾。因此建议使地图静态(如果需要从外部访问,也将其公开)。
将文件加载到地图
将其存储在文件中
键1 =值 键2 =值 .... ....
现在使用BufferedReader,如下所示
BufferedReader reader = new BufferedReader(new FileReader(new File("pathname")));
String line = null;
Map<String, Integer> map = new HashMap<String, Integer>();// it should be static - whereever you define
while ((line = reader.readLine()) != null) {
if (line.contains("=")) {
String[] strings = line.split("=");
map.put(strings[0], Integer.parseInt(strings[1]));
}
}
类加载器是在启动应用程序时在内存中加载类的东西。 Tomcat还有它的类加载器,它在内存中加载所需的类(Classes而不是对象)。现在我们知道静态变量与类而不是对象相关联。因此,静态成员与类一起加载到内存中。在许多其他情况下,您将创建类的对象并使用它。如果你在内存中加载了数百万个对象 - 你很快就会缺少它。所以java有一个叫垃圾收集器的东西。此垃圾收集器从内存中删除不需要的/旧对象以回收它。垃圾收集器删除对象而不是类,因此静态成员仍然保留在内存中。
答案 1 :(得分:2)
您可以静态初始化静态块中的静态变量,如下所示:
private static Map<String, Integer> map = new HashMap<String,Integer>();
static {
fillMap(map, "filename.txt");
}
private static void fillMap(Map<String, Integer> map, String fileName) {
// here comes file reading code with loop
}
如何阅读文件,请参阅此Reading a plain text file in Java。
只要在应用程序启动时初始化其所有静态映射。
答案 2 :(得分:1)
尝试将文本文件加载到应用程序中:Read from a Text File into a hash map or list
当我刚刚开始编程时,我知道我很想使用很多全局变量。事实证明,这通常不是最好的策略(见http://c2.com/cgi/wiki?GlobalVariablesAreBad)。
也许您可以在main方法中首先加载字典,然后将其传递给稍后需要的其他方法。
答案 3 :(得分:1)
您可以在web.xml文件中定义监听器:
<listener>
<listener-class>my.Listener</listener-class>
</listener>
你实现了这个类:
package my;
public class Listener implements javax.servlet.ServletContextListener {
public void contextInitialized(ServletContext context) {
File file = new File();
fileEntries = ... // load your entries
for (Object[] line : fileEntries) {
YourClass.get().addElement((String) line[0], Integer.parseInt(line[1].toString());
}
}
}
如果你想访问你的Map应用程序范围,只需创建一个单例或使用Spring来管理类,如果单例执行类似的操作:
public class YourClass {
private static final YourClass INSTANCE = new YourClass();
private Map<String, Integer> yourMap;
private YourClass() {
yourMap = new HashMap<>();
}
public static final YourClass get() {
return INSTANCE;
}
public void addElement(String key, Integer value) {
yourMap.put(key, value);
}
public Integer getValueForKey(String key) {
return yourMap.get(key);
}
}
因此您可以通过以下方式从应用程序的任何位置访问元素:
YourClass.get().getValueForKey("yourKey");
答案 4 :(得分:1)
我建议您使用Properties来存储/加载键/值对,并实现Singleton
模式以访问这些属性。像这样:
public class EnDict {
private Properties properties;
private static EnDict enDictInstance;
private EnDict {
properties = new Properties();
FileInsputStream fis = null;
try{
fis = new FileInputStream("yourPropertiesFile.properties");
properties.load(fis);
fis.close();
} catch(IOException ex) {
/* log the exception */
} finally {
try {
fis.close();
} catch (IOException ignored) {}
}
}
public static EnDict getEnDictInstance(){
if(enEdictInstance == null) {
enEdictInstance = new EnEdict();
}
return enEdictInstance;
}
public Integer getValue(String key){
String value = properties.getProperty(key);
return Integer.valueOf(value);
}
public void setNewWord(String word, Integer value){
properties.setProperty(word, value.toString());
}
public void saveProperties() {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("yourPropertiesFile.properties");
properties.store(fos, "Some comments");
fos.close();
} catch (IOException ex) {
/* log the exception */
} finally {
try{
fos.close();
} catch(IOException ignored){}
}
}
}
正如@Mauren指出的那样,请记住Properties
不允许null
值。
您也可以使用.properties
文件代替XML
个文件。见Loading Properties from XML
答案 5 :(得分:0)
要将来自不同资源的常量加载到不同的java类,可以使用apache commons配置库http://commons.apache.org/proper/commons-configuration/
对于应用程序启动,您可以使用
<servlet>
<servlet-name>StartUp</servlet-name>
<display-name>StartUp Servlet</display-name>
<servlet-class>foo.bar.YourStartUpServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>