2

I have an interesting question on initialization. I have the following code:

public class ErrorLookupProvider {  

private static final ErrorLookupProvider INSTANCE = new ErrorLookupProvider();

private  static Map<Long, List<String>> map = new HashMap<Long, List<String>>();

    private ErrorLookupProvider() {
        init();
    }

    private void init() {
        map.put(123L, ImmutableList.of("abc", "def"));
    }

    public static ErrorLookupProvider getInstance() {
        return INSTANCE;
    }
}

Now when I call ErrorLookupProvider.getInstance(), I hit an NPE. The map inside init() is not initialized with the new HashMap.

If I change the declaration of map to be final, then I see that it is initialized. Or, even if I remove static and make it a private class variable as private Map<.....> that works too.

I haven't been able to figure out why this happens. Can someone explain what is happening here?

2
  • Will that even compile with the non-long map key? Commented Jun 15, 2012 at 23:12
  • My mistake, I missed out the 123L Commented Jun 15, 2012 at 23:17

3 Answers 3

5

Switch the order of the map and singleton instance initializations.

Static initialization occurs in the order it's encountered in the source.

See JLS 12.4.2 Detailed Initialization Procedure, steps 6 (the final part) and 9 (the "order" part).

(The singleton implementation and mucking with statics in a ctor, separate issue.)

Sign up to request clarification or add additional context in comments.

2 Comments

Oh! That's because of the sequencing of statics. If I put the map first, it would be ok I think. Which leads me to the question - Is this even allowed? private static final ErrorLookupProvider INSTANCE = new ErrorLookupProvider(); Going by the sequencing, I'm initializing my static variable by calling the constructor. This means the constructor is called even before the variable is initialized. Is this usage incorrect then? Usualy, the init happens as follows: 1. Static members 2. Static blocks 3. Member vars 4. Constructor Now, I'm trying to jump from 1 to 4. Should this be disallowed?
@Sudoer Yep, that's what we said--order matters :) Of course it's allowed--it works, doesn't it?
2

quoting from http://javapapers.com/core-java/explain-the-final-keyword-in-java/

A variable that is declared as final and not initialized is called a blank final variable. A blank final variable forces the constructors to initialise it.

That is why when declared final it is initialised

4 Comments

Is it even valid to call private static final ErrorLookupProvider INSTANCE = new ErrorLookupProvider(); The class initialization is first the static vars, static blocks, member vars and then the constructor. However, in this case, is it even valid to call the constructor to initialize the static variable?
yes that would be fine. Just a minor comment to your code, you could use as a declaration of your HashMap this private static Map<Long, List<String>> map = new HashMap<>();
NO NO NO, when declared final then if the variable is not initialised by you, the constructor will force it to be initialised
@MaVRoSCy that new shorter syntax is nice, but only works in Java 7.
2

ADDED: Order matters. Put the declaration for your static map before the declaration of INSTANCE. The Java compiler is a bit stupid about ordering...

Since map is static, it is shared among all instances of ErrorLookupProvider. Therefore, it is probably a mistake to play with it in the constructor. If you create multiple ErrorLookupProviders, you will redundantly add to the map many times. Instead, initilize it in a static initializer block. Or, if it is really meant to be independent between instances of ErrorLookupProvider, don't make it static.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.