Woozle Wuzzle
Java instance initializers

I have been playing around with some UI mock ups lately and it is often that I have code that looks like the following:

    ...
    add(new Label("Some text"));
    ...

If I want to see what Some text looks like in a different color or font then I need to extract the label creation to a local variable and then set the appropriate members. Since I'm a lazy lazy man I was getting tired of this. Luckily I remembered about instance initializers. Because of instance initializers you can do the following:

    ...
    add(new Label("Some text") {{ setFont(someFont); }});
    ...

{{ and }} are not new tokens. Writing it another way makes it more clear:

    ...
    add(new Label("Some text")
    {
        { 
            setFont(someFont); 
        } 
    });
    ...

The only question that remains is: when is the instance initializer executed? You can read section 8.8.5.1 of the JLS if you want. (The problem that I have with section 8.8.5.1 is that it is for explicit constructor invocations which doesn't seem to be the case for this example but I cannot find another reference to instance initializers in the JLS.) The code below provides a clearer answer to the question.

    class PreTest {
    
        {System.err.println("PreTest First");}

        public PreTest() {
            System.err.println("PreTest constructor");
        }
    
        {System.err.println("PreTest Second");}
    }

    class Test extends PreTest {
        {System.err.println("Test First");}

        public Test() {
            System.err.println("Test constructor");
        }
    
        {System.err.println("Test Second");}
    
        public Test(final int number) {
            this();
            System.err.println("Test constructor(" + number + ")");
        }
    
        {System.err.println("Test Third");}
    
        public void method() {
            System.err.println("Test method");
        }
    
        {System.err.println("Test Fourth");}
    }
    
    class Dummy {
        public Dummy() {}
        public void go(Test test) {}
    }
    
    final Dummy dummy = new Dummy();
        dummy.go(new Test(10) {{ method(); }});

When executed, the following is output:

    PreTest First
    PreTest Second
    PreTest constructor
    Test First
    Test Second
    Test Third
    Test Fourth
    Test constructor
    Test constructor(10)
    Test method

An instance initializer is executed during construction but after all other instance initializers and all (appropriate) constructors have finished.

I should point out that this "trick" is also great in unit tests for populating collections.

    ...
    something.addList(new ArrayList() {{ add("1"); add("2"); add("3"); }});
    ...
    foo.addMap(new HashMap() {{ put("1", "one"); put("2", "two"); }});
    ...
Comments
Comment by Brandon Franklin at February 8, 2005 07:41 PM

Excellent tip! I'm one of the few people who seems to even remember that instance initializers exist at all :) and I've /certainly/ never seen them used in this novel fashion. Very clever.

 

Comment by Jim Gu at June 19, 2005 11:52 PM

Good example!

 

Comment by Rory Winston at November 12, 2006 04:07 PM

Good tip! I've always been a bit annoyed at the relative verbosity of initializing a HashMap compared to Ruby or Javascript. This syntax makes it a bit easier. Surprised I haven't seen it used more.

 

Comment by Patrick Finnigan at July 13, 2007 09:38 AM

Good example! Your example is very readable and gives me a very clear understanding of instance initializers and their utility.

 

Comment by Kirill at January 22, 2008 01:46 PM

Your test actually shows that all instance initializers are executed BEFORE constructor.

I just got the same puzzling answer myself, and found your notice to confirm.

Strange thing is, that in my own tests I assigned some instance variables in initializers. So, initializer assigns those vars BEFORE constructor (and supposedly those vars should not even exist), and constructor overrides them.

In fact, I expected the opposite to happen.

 

Post a comment













Remember personal info?






Creative Commons License Unless otherwise expressly stated, all original material of whatever nature created by Rob Grzywinski and included in this weblog and any related pages, including the weblog's archives, is licensed under a Creative Commons License.