2

我正在开发一个小项目,一个 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 保存在内存中的特定部分的答案。它类似于类中的 ASP.NETApplication_Start方法Global

我对编程非常陌生,特别是对 Java 来说,所以也许我完全被误导了如何是完成这项任务的最佳方式。如果是这样的话,一些小费将不胜感激。

我正在使用 Servlet、JSP 和 Tomcat。

编辑:实际上,它不会只有一张地图。会有几个 Map,这些 Map 可以有一些相同的键。

4

6 回答 6

4

将此映射定义为静态 - 它将在内存中,直到加载此类的类加载器未被垃圾收集。

我上面说的是:http: //docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.7

静态成员链接到类,上面的规范说在类加载器到位之前不会卸载类。

而对象确实会被垃圾收集。因此建议将地图设为静态(也将其公开,以防需要从外部访问)。

并将文件加载到地图中

将其存储在文件中

键1=值1 键2=值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 也有它的类加载器,它在内存中加载所需的类(类而不是对象)。现在我们知道静态变量与类而不是对象相关联。因此静态成员与类一起加载到内存中。在许多其他情况下,您将创建该类的对象并使用它。如果您在内存中加载了数百万个对象 - 您很快就会缺少它。所以java有一个叫做垃圾收集器的东西。此垃圾收集器从内存中删除不需要的/旧对象以回收它。垃圾收集器删除对象而不是类,因此静态成员仍保留在内存中。

于 2013-09-06T14:35:07.980 回答
3

您可以像这样在静态块中静态初始化静态变量:

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
}

如何读取文件见类似Read a plain text file in Java

至于它的所有静态地图将在应用程序启动时初始化。

于 2013-09-06T14:23:59.460 回答
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文件。请参阅从 XML 加载属性

于 2013-09-06T14:49:04.777 回答
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");
于 2013-09-06T14:35:07.960 回答
1

试试这个将文本文件加载到您的应用程序中:从文本文件中读取到哈希映射或列表中

当我刚开始编程时,我知道我很想使用很多全局变量。事实证明,这通常不是最好的策略(参见http://c2.com/cgi/wiki?GlobalVariablesAreBad)。

也许您可以首先在 main 方法中加载字典,然后将其传递给稍后需要的其他方法。

于 2013-09-06T14:31:10.917 回答
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> 
于 2013-09-06T14:32:14.357 回答