views:

231

answers:

5

I am absolute clueless why the following code keeps throwing NullpointerExceptions. I was not able to understand or debug this (its stripped down code from a larger class)...

The code is based on the "Enum Pattern" and I want to keep a List/Map of all "Constants" that are contained in the class (I might be using Reflection for this but using a List/Map is much easier...)

   public class Country {

        public static final Country SWITZERLAND = new Country("SWITZERLAND");

        private static ArrayList<Country> countries = new ArrayList<Country>();

        private  Country(String constname) {     
             //constname is currently not used (I will use it for a Key in a Map)
            System.out.println(constname);
            System.out.println("Ref debug:"+this);

            //Ad this to the Countries
            Country.countries.add(this);
        }
    }

Help would be very much appreciated. What am I missing here?

+5  A: 

SWITZERLAND, being static, is potentially initialized before countries, which is also static. Therefore, countries is still null in the constructor call of SWITZERLAND.

To force a well-defined order of initialization, use a static block:

public class Country {

    public static final Country SWITZERLAND;

    private static ArrayList<Country> countries;

    static {
        countries = new ArrayList<Country>();
        SWITZERLAND = new Country("SWITZERLAND");
    }
}
Konrad Rudolph
Order of initialization is always well-defined. It is performed in textual order. +1 for static initialization block. The order of execution is more clear for the reader this way.
Tadeusz Kopec
+4  A: 

To expand on what Konrad said, the static variable initializers are executed in textual order (as specified in JLS section 8.7). If you put the ArrayList first, it will work:

public class Country {    
    private static ArrayList<Country> countries = new ArrayList<Country>();

    public static final Country SWITZERLAND = new Country("SWITZERLAND");

...

Konrad's suggestion of using a static constructor to keep the order clearly specified is a good one though.

Are you using Java "pre 1.5"? If not, use a straight enum...

Jon Skeet
+1 … I’m not actually very fluent in Java, hence I wasn’t sure about the order of initialization. Since Jon says that it’s textual, this solution is superior to the `static` block (IMHO).
Konrad Rudolph
+1  A: 

'Country' constructor call to initialize SWITZERLAND static field happens before initialization of countries list. If you change order of static field definition it will work better.

Tadeusz Kopec
A: 

Hi,

I think code bellow may work .Constructor of class have to define as public method not private.

Country(String constname) {
//constname is currently not used (I will use it for a Key in a Map) System.out.println(constname); System.out.println("Ref debug:"+this);

        //Ad this to the Countries
        Country.countries.add(this);
    }
prakash.panjwani
The visibility of the constructor has got nothing to do with the problem.
mikej
+3  A: 

Because I think this deserves more than the cursory mention Jon gave it:

The "typesafe enum pattern" is obsolete!

Unless you are forced to use an ancient Java version (pre 1.5, which isn't even supported anymore by Sun), you should use Java's real Enums, which save you a lot of work and hassles (because old-style typesafe enums are very hard to get right) and are just all around awesome.

Michael Borgwardt