8

Possible Duplicate:
How is an instance initializer different from a constructor?

When all the required work can be done inside the constructor, then why do we still need non-static block in Java?

EDIT: What about normal classes for which non-static blocks run everytime before the constructor?

Community
  • 1
  • 1
Ashwyn
  • 659
  • 1
  • 6
  • 18

2 Answers2

15

In additional to @Bohemian's answer.

If you have multiple constructors an intialiser block avoid duplication.

public class A {
     final Map<String, String> map = new HashMap<String, String>(); {
        // put things in map.
     }
     final int number; {
        int number;
        try {
            number = throwsAnException();
        } catch (Exception e) {
            number = 5;
        }
        this.number = number;
     }

     public A() { /* constructor 1 */ }
     public A(int i) { /* constructor 2 */ }
}

What about normal classes for which non-static blocks run everytime before the constructor?

Technically the order is

  • the super constructor is always called first
  • all the initializer blocks in order of appearence.
  • the constructor code

In reality all this code is in the byte code for each constructor so there is nothing before or after the constructor at runtime.


Before there is any more confusion as to the order of initialization

public class Main extends SuperClass {
    {
        System.out.println("Initialiser block before constructor");
    }

    Main() {
        System.out.println("Main constructor");
    }

    {
        System.out.println("Initialiser block after constructor");

    }

    public static void main(String... args) {
        new Main() {{
            System.out.println("Anonymous initalizer block");
        }};
    }
}

class SuperClass {
    SuperClass() {
        System.out.println("SuperClass constructor");
    }
}

prints

SuperClass constructor
Initialiser block before constructor
Initialiser block after constructor
Main constructor
Anonymous initalizer block
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • It looks a bit confusing to place the leading parenthesis on the same line as the declaration of `number`. – obataku Aug 08 '12 at 17:39
  • @veer Its a styling issue. Its to show that block relates specifically to that field. – Peter Lawrey Aug 08 '12 at 17:40
  • @PeterLawrey: Why can't this be done inside the constructor? – Ashwyn Aug 08 '12 at 17:44
  • 1
    It can by repeating all the code in each constructor or finding a way to use `this()` The problem is remembering to add the bits before and after if you add a constructor. Its much simpler not to need to do this. – Peter Lawrey Aug 08 '12 at 17:48
  • @PeterLawrey: I have read that non-static blocks run before the constructor everytime an object is created. I am not able to understand the last part of the statement, 'Technically the order is...' – Ashwyn Aug 08 '12 at 17:49
  • Please don't use the self-registering constructor anti-pattern! (Or any mutable static/global state, nor is it a particularly good idea to have `this` escape from the constructor into the wider context.) – Tom Hawtin - tackline Aug 08 '12 at 17:50
  • 1
    @Ashwyn, good point., fixing. – Peter Lawrey Aug 08 '12 at 17:56
  • @TomHawtin-tackline I would agree unless you are sure its the last thing the constructor does (which is hard to be sure unless the class is `final`) – Peter Lawrey Aug 08 '12 at 17:58
  • 2
    @PeterLawrey Instance blocks for anonymous classes execute *after* the constructor, in order of appearance. Maybe distinguish that in your answer from execution order for instance blocks within a class. (ps congrats on 100K, and for your java connector character answer making the newsletter!). – Bohemian Aug 08 '12 at 18:12
  • @Bohemian I have added an example to clarify the order. – Peter Lawrey Aug 08 '12 at 18:17
  • @Bohemian Thank you (which newsletter? he asked quickly ;) – Peter Lawrey Aug 08 '12 at 18:18
  • @Bohemian Thank you for pointing it out. You learn something every day. :D – Peter Lawrey Aug 08 '12 at 18:21
  • @PeterLawrey The weekly stackoverflow newsletter email (you can subscribe). Your answer was the top one in the "Top new questions this week" section of Tuesday 7th August's edition. Way to cross over 100K! btw, for completeness you could add an anonymous initializer block to your example code: `new Main() {{System.out.println("Anonymous initalizer block")}};` and add that to the output (last) – Bohemian Aug 08 '12 at 18:30
8

You can use it with an anonymous class:

new MyClass() {
    {
         // do something extra on construction (after the constructor executes)
    }
}

I find this is particularly useful for initializing "look up" maps (ie fixed contents) in place:

Map<String, String> map = new HashMap<String, String>() {
    {
        put("foo", "bar");
        put("one", "two");
        // etc
    }
};

FYI, this is sometimes (poorly) called "double brace initialization", when in fact it's simply employing an initializer block.

Although such an anonymous class is technically a subclass, the beauty of this is shown when comparing using this technique with a more traditional one in creating an unmodifiable map:

Compare this straightforward one-liner, which places data and assignment together:

private static final Map<String, String> map = Collections.unmodifiableMap(
    new HashMap<String, String>() {{
        put("foo", "bar");
        put("one", "two");
        // etc
    }});

With this mess, which must create a separate object due to final only allowing one assignment:

private static final Map<String, String> map;

static {
    Map<String, String> tempMap = new HashMap<String, String>();
    tempMap.put("foo", "bar");
    tempMap.put("one", "two");
    // etc
    map = Collections.unmodifiableMap(tempMap);
}

Also note that with the mess version, the two statements need not be adjacent, so it can become less obvious what the contents of the unmodifiable map is.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 2
    Note that initializing containers like this (known as ["double brace initialization"](http://c2.com/cgi/wiki?DoubleBraceInitialization)) creates a subclass rather inappropriately -- similar to how subclassing `Thread` is considered inappropriate when you merely want to implement `Runnable`. Careful when abusing inheritance; one example mentioned there is how it can break a common implementation of `equals`. You should probably look into using a [collection factory method](http://c2.com/cgi/wiki?VarargsCollectionFactoryMethod). – obataku Aug 08 '12 at 17:35
  • @veer Nice link/read. I think it's better to check against the CTT of the class (and/or any supported superclasses) in equals, though .. –  Aug 08 '12 at 17:40
  • @veer I absolutely do not consider this an "abuse of inheritance"; it's simply populating an object in-line. I use this frequently in my code without any problems. See edited answer. – Bohemian Aug 08 '12 at 18:08
  • @Bohemian you can simplify your code even further by using a factory method, e.g. `Collections.unmodifiableMap(newHashMap("foo", "bar", "one", "two", ...))`. Aside from that, I think you should look into the [Liskov Substitution Principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle). – obataku Aug 08 '12 at 18:14
  • @veer I'm well aware of Liskov etc, but out of the box java doesn't provide map builders, and with this you don't need to write/find one. And consider building a `Map` (which I have) - java doesn't support mixed varargs, so it becomes trickier to type it. Also, you define and can invoke convenience methods, which all work just fine. Also also, `HashMap` is such a basic utility class, that no one (except you it seems) cares that it has been "subclassed". I encourage my team to use this pattern, and I refactor to convert ugly versions above to it. So there :P – Bohemian Aug 08 '12 at 18:26
  • 1
    @Bohemian I made an error, `Maps.newHashMap`*. But regardless, it could return a `Map` (though it'd be rather pointless given the method contract). I'm not trying to be a pedant, but one should take care when using inheritance in an unconventional way like that. – obataku Aug 08 '12 at 18:27