Java 如何在应用程序启动时将文本文件加载到 HashMap?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18660027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 09:56:23  来源:igfitidea点击:

How to load text file to HashMap at application startup?

java

提问by Rafael Eyng

I'm developing a little project, a web application where I run some analysis on data based on user text input.

我正在开发一个小项目,一个 Web 应用程序,我在其中根据用户文本输入对数据进行一些分析。

To do so, I need to use a Map where I have words and corresponding scores for that word.

为此,我需要使用地图,其中包含单词和该单词的相应分数。

This is what I tried:

这是我尝试过的:

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
        }
    }
}

It works, but this way I need to have the key/value pairs hard-coded in my class. So, if I want to add more pairs, I have to write code, instead of just adding pairs do a text file. Doesn't seem good.

它有效,但这样我需要在我的班级中硬编码键/值对。所以,如果我想添加更多对,我必须编写代码,而不是仅仅添加对来做一个文本文件。好像不太好

So I want to obtain this pairs from a text file. Also, I need this Map to be created when the application starts, so when any user makes a request the Map is already loaded, and can be used by the analysis logic. I mean, the Map must be in memory before the first request happens, and last in memory after that, to be used in subsequent requests. And it need to be visible from anywhere in my application (maybe this part wasn't very clear, but I don't know how to explain it better).

所以我想从文本文件中获取这些对。另外,我需要在应用程序启动时创建这个 Map,所以当任何用户发出请求时,Map 已经加载,并且可以被分析逻辑使用。我的意思是,Map 必须在第一个请求发生之前在内存中,然后在内存中最后一个,以便在后续请求中使用。而且它需要在我的应用程序中的任何地方都可见(也许这部分不是很清楚,但我不知道如何更好地解释它)。

I've tried some research, but haven't found answers to this specific part of keeping the Map in memory since the application start. It's something similar to ASP.NET Application_Startmethod, in the Globalclass.

我已经尝试了一些研究,但还没有找到自应用程序启动以来将 Map 保留在内存中这一特定部分的答案。它类似于 ASP.NETApplication_Start方法,在Global类中。

I'm very new to programming and specially to Java, so maybe I'm completely misled about how would be the best way of achieving this task. If that is the case, some tip would be appreciated.

我对编程非常陌生,特别是对 Java,所以也许我完全被误导了如何是完成这项任务的最佳方式。如果是这种情况,将不胜感激。

I'm using Servlets, JSP and Tomcat.

我正在使用 Servlet、JSP 和 Tomcat。

Edit: Actually, it would not be only one Map. There will be several Maps, and those Maps can have some keys that are identical.

编辑:实际上,它不仅仅是一张地图。将会有多个 Maps,这些 Maps 可以有一些相同的键。

采纳答案by Ashay Thorat

Define this map as static - it will be in memory until class loader who loaded this class is not garbage collected.

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

I say above by refering : http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.7

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

Static member are linked to class and above specification says that classes will not be unloaded until class loader is in place.

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

Whereas objects do get garbage collected. Hence suggested to make map static(make it public too in case needs access from outside).

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

And for loading file into map

并将文件加载到地图中

store it in file as

将其存储在文件中

key1=value1 key2=value2 .... ....

key1=value1 key2=value2 .... ....

now use BufferedReader as below

现在使用 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]));
            }
        }

Class loader is something which loads classes in memory while starting the application. Tomcat also has its classloader which loads required classes in memory(Classes and not objects). Now we know that static variables are associated with class and not object. So static members are loaded in memory along with class. IN many other cases you would be creating object of the class and use it. If you have millions of objects loaded in memory- You will be soon short of it. So java have something called garbage collector. This garbage collector removes unwanted/old objects from memory to recycle it. Garbage collector removes objects not classes and hence static member still remains in memory.

类加载器是在启动应用程序时在内存中加载类的东西。Tomcat 也有它的类加载器,它在内存中加载所需的类(类而不是对象)。现在我们知道静态变量与类相关联,而不是与对象相关联。因此静态成员与类一起加载到内存中。在许多其他情况下,您将创建类的对象并使用它。如果您在内存中加载了数百万个对象 - 您很快就会缺少它。所以java有一种叫做垃圾收集器的东西。这个垃圾收集器从内存中删除不需要的/旧的对象以回收它。垃圾收集器删除的是对象而不是类,因此静态成员仍然保留在内存中。

回答by svobol13

You can staticaly initialize static variable in static block like this:

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

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
}

How to read file see something like this Reading a plain text file in Java.

How to read file see like this Reading a plain text file in Java

As far as its all static map will be initialized on application startup.

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

回答by lucas

Try this for loading the text file into your application: Read from a Text File into a hash map or list

尝试将文本文件加载到您的应用程序中:Read from a Text File into a hash map or list

When I was just starting to program, I know I was tempted to use a lot of global variables. As it turns out, this is usually not the best strategy (see http://c2.com/cgi/wiki?GlobalVariablesAreBad).

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

Perhaps you can load your dictionary first thing in your main method, and pass it through to other methods that need later on.

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

回答by Alireza Fattahi

For loading the constants from different resources to different java classes you can use apache commons configuration library http://commons.apache.org/proper/commons-configuration/

要将常量从不同的资源加载到不同的 java 类,您可以使用 apache commons 配置库http://commons.apache.org/proper/commons-configuration/

For application start up you can use

对于应用程序启动,您可以使用

<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> 

回答by OscarG

You can define a Listener on web.xml file:

您可以在 web.xml 文件上定义一个侦听器:

<listener>
    <listener-class>my.Listener</listener-class>
</listener>

and you implement the class:

然后你实现了这个类:

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());
       }
   }
}

if you want to access your Map application-wide, just create a singleton or use Spring to have the class managed, if a singleton do something like:

如果您想在整个 Map 应用程序范围内访问您的 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);
     }
}

and so you can access the elements from anywhere in the application via:

因此您可以通过以下方式从应用程序的任何位置访问元素:

YourClass.get().getValueForKey("yourKey");

回答by dic19

I would suggest you use Propertiesto store/load key/valuepairs and implement Singletonpattern to access these properties. Something like this:

我建议您使用属性来存储/加载键/值对并实现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){}
         }
     }
}

As @Mauren pointed out just keep in mind Propertiesdoesn't allow nullvalues. Also instead of .propertiesfiles you can use XMLfiles. See Loading Properties from XML

正如@Mauren 指出的那样,请记住Properties不允许使用null值。.properties您也可以使用XML文件代替文件。请参阅从 XML 加载属性