jan
jan

Reputation: 131

Adding "this" reference to Array fails in Java Constructor

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?

Upvotes: 0

Views: 403

Answers (5)

Michael Borgwardt
Michael Borgwardt

Reputation: 346377

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.

Upvotes: 4

Tadeusz Kopec for Ukraine
Tadeusz Kopec for Ukraine

Reputation: 12413

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

Upvotes: 1

Prakash Panjwani
Prakash Panjwani

Reputation: 2572

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

Upvotes: -1

Jon Skeet
Jon Skeet

Reputation: 1502036

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

Upvotes: 4

Konrad Rudolph
Konrad Rudolph

Reputation: 545865

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

Upvotes: 5

Related Questions