Constructor in the class of static methods

I have a class of static methods that can be executed on a map stored inside a class, and I want the map to be configured when the class is called. I tried using a private contructor, but it is not called. Relevant parts of my code:

public class MyClass { private static final String KEYS = "ABC"; private static final String[] DATA = {"AAA", "BBB", "CCC"}; private static HashMap<Character, String> myMap; private MyClass() { System.out.println("Running constructor"); populateMyMap(); } private static void populateMyMap() { myMap = new HashMap<Character, String>(); for (int i=0; i < KEYS.length; i++) { myMap.put(KEYS.charAt(i), DATA[i]); } } //various static methods } 

Is the private constructor right to use here, and if so, what am I doing wrong?

Sorry if this is a duplicate; I tried to find the answers, but I'm not sure what to look for!

+4
source share
4 answers

The static initializer block is mentioned in several other answers. But in practice, I find the following idiom more often in the wild:

 public class MyClass { private static HashMap<Character, String> myMap = createMyMap(); private static HashMap<Character, String> createMyMap() { HashMap<Character, String> myTmpMap = new HashMap<Character, String>(); for (int i=0; i < KEYS.length; i++) { myTmpMap.put(KEYS.charAt(i), DATA[i]); } return myTmpMap; } } 
+5
source

No, private constructor is not what you want. The constructor initializes an instance of your class (when calling new MyClass() ), but the static state does not belong to the instance and therefore should not be initialized by the constructor. The initialization that you want to perform the first time you load the class must be in a static block placed at the class level.

 static { populateMyMap(); } 

But you should never use a static (global) state. The static state makes your system unacceptably difficult to test, it is more nuanced than the state of the instance (for example, you have one copy to load the class), and it is usually more difficult to make the thread safe.

Consider making your card a member of an instance of your class.

+8
source

Use a static initializer:

 public class MyClass { static { //init } } 
+3
source

There are two ways to achieve this. One of them is to make the populateMyMap method a static initializer (or the approach suggested by AH). Then execution is guaranteed before the first static call. This is usually the best way, assuming either the cost of running populateMyMap is small enough to not be noticed, or if you intend to use the functionality of this class almost every time the application starts.

An alternative approach is what you would use if running populateMyMap is something that takes a considerable amount of time. And either you cannot use the functionality for some executions of the application, or you want to delay the execution of populateMyMap until the data is needed, so as not to increase the launch time.

If the second approach is what you want, you should switch structures and use singleton, not static methods. Add non-static methods (and data) and each user of them will receive a Singleton instance before calling the method on it. Have the "populateMyMap" called in the (private) constructor. Yes, I know that singleton have a bad reputation and people always say “avoid them because they just mask global methods”, but static methods are also just global methods. You have nothing to lose. And in this way you do not pay the cost to execute populateMyMap until you need it (or if you need it).

A WARNING. If your data structures are not immutable, that is, they can be changed after they are initialized, then you probably should not use any of these structures.

0
source

Source: https://habr.com/ru/post/1390692/


All Articles