4

I have a class with two methods load() and getValue(). The load function loads a set of key value pairs from a file onto a hashMap and the getValue(Object key) method is used to extract values for keys passed to it.

My problem is that I want to create an Object of the class such that load() should be executed only once (to load values into memory) and thereafter the getValue() method should be able to work on this data, each time its called.

What is the best approach to solve this problem? I am quite new to Java and OOP, so please feel free to modify either the question or the title to make it more clear.

4

11 回答 11

9

You can use a static initializer block for your class. This is executed only once for a class.

http://www.glenmccl.com/tip_003.htm

于 2012-04-20T06:37:23.763 回答
3

You can make so that the load() method is private and called in the constructor (when your object is made/class initiated.

It would look something like this:

public class YourClass {

    private Map map;

    public YourClass() {
        load();
    }

    private void load() {
        // Load the data here
    }

    public Object getValue(int key) {
        return map.get(key);
    }

}
于 2012-04-20T06:38:10.193 回答
2

What you need is the Singleton Pattern. So basically you could do something like this:

public class MySingleton
{
     private static Map<String, String> myMap = null;
     private void load()
     {
         myMap = ...//load your contents here
     }

     public static String getValue(String key)
     {
          if (myMap == null)
          {
              load();
          }

          return myMap.get(key);
     } 
}

The above code will allow you to load the HashMap once in your application. You will be exposing only one method, being the load() while you leave the initialization code to a private method to which no one outside your class has access to.

Just as a heads up, you will need to introduce synchronized blocks if you plan to use this in a multi-threading environment, as per the Wikipedia example.

I am assuming that the key-value pairs are both strings, but you can do whatever datatype you want. If you want to store the HashMap between application usages, you can store it to disk, just make sure that the elements making up the HashMap implement the Serializable interface.

于 2012-04-20T06:35:07.903 回答
2

Maybe these approaches are too obvious but I thought I’d mention them anyway… singletons and other static “magic” usually has quite some pitfalls that might bite you later on.

  1. Only call load() once. This is probably the most simple solution.
  2. Remember in load() that the method was already called (add a boolean member, set it to true at the end of the method, check for true at the beginning of the method and simply return in that case).
于 2012-04-20T06:56:19.737 回答
1

@tom pointed out a very good solution for the given problem. However, it can also be solved by using a singleton pattern. Since the ones named before are not threadsafe and therefore might cause problems later on, heres my threadsafe solution for this particular problem:

public Enum MyClass {
   INSTANCE;

   public static MyClass getInstance() {
          INSTANCE.load();
          return INSTANCE;
   }

   private void load() {
          // Load your data
   }
}

Given code uses Enum singleton pattern and works with JDK 5+

于 2012-04-23T12:22:08.297 回答
0

Make use of singleton pattern. Make sure only one object can be created for the class. Include the code to load the values in load() in constructor, as given in this example. This will solve your problem.

于 2012-04-20T06:36:54.130 回答
0

Make your Map object a static variable and use static initialization .

于 2012-04-20T06:38:40.837 回答
0

It sounds like you simply must call load() in the constructor. To ensure it is called with any constructor, call it from other constructors.

And by the way, a static initializer sounds nice, but is different, and in some cases is a bad practice. Some people believe in never using a static initializer ever, because you cannot unit test it, and in some cases you can't debug it (it is called when the class is first loaded, not when the constructor is called, or when a method is called, etc. so it depends on what version and platform you have for the JVM!)

example 1:

class MyObj {
    private load() {
        //private so it can't be called elsewhere by mistake (except by you in this file)
    }

    public MyObj() {
        load();
    }
    public MyObj(Collection values) {
        MyObj();
        //next deal with values (duplicate code)
    }
    public MyObj( Collection keys, Collection values) {
        MyObj();
        //next deal with keys and values (some duplicate code)
    }

    ...
}

example 2: (maybe more complicated causing NullPointerExceptions for new developers, but better for advanced coders because it avoids duplication)

class MyObj {
    public MyObj( Collection keys, Collection values) {
        load();
        //next deal with keys and values (no duplication this time)
    }
    public MyObj(Collection values) {
        MyObj(null, values);
    }
    public MyObj() {
        MyObj(null, null);
    }

    ...
}

If you want something more complicated, eg. a single object to exist at any time, you want to use a singleton, and possibly a factory. (A factory means a single object exists per factory rather than overall, and has other benefits not mentioned here).

于 2012-04-20T06:46:54.810 回答
0

I've got a look to all the above solutions! First, piece of codes that are executed once are generally provided into the constructor, as suggested by j0ntech! Second, if you don't want to let people run twice or more a method, you have to control the method call from inside with something like a boolean that is set to false after the first call of load(). E.g.

private boolean enabledLoad = true;

public void load( ...something here...) {
   if(enabledLoad){
     //do something       
   }
   enabledLoad = false;
} 

Very simple...

于 2012-04-20T06:55:27.160 回答
-1

You can serialize the class which you want to use again and again without loss of the values holding to that class and obviously without loading values again....

于 2012-04-20T06:33:11.837 回答
-1

You can also go for making static methods which means they will not update the existing data even if the method called.

于 2012-04-20T06:44:04.633 回答