35

What is the sense of "Instance Initializers" in Java ?
Can't we just put that block of code at the beginning of the constructor instead?

Ahmed Waheed
  • 1,281
  • 5
  • 21
  • 39

4 Answers4

43

I use them very often, typically for creating and populating Map in one statement (rather than using an ugly static block):

private static final Map<String, String> CODES = new HashMap<String, String>() {
    {
        put("A", "Alpha");
        put("B", "Bravo");
    }
};

One interesting and useful embellishment to this is creating an unmodifiable map in one statement:

private static final Map<String, String> CODES = 
    Collections.unmodifiableMap(new HashMap<String, String>() {
    {
        put("A", "Alpha");
        put("B", "Bravo");
    }
});

Way neater than using static blocks and dealing with singular assignments to final etc.

And another tip: don't be afraid to create methods too that simplify your instance block:

private static final Map<String, String> CODES = new HashMap<String, String>() {
    {
        put("Alpha");
        put("Bravo");
    }

    void put(String code) {
        put(code.substring(0, 1), code);
    }
};
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 3
    For people using instance initializers for collection population, look to the [Guava Library](http://code.google.com/p/guava-libraries/) as a more elegant and powerful alternative. The [`Maps`](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Maps.html) class provides nice Map utilities and their `Immutable*` classes are particularly nice for the use case described here, see [`ImmutableMap`](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html). – dimo414 Aug 07 '13 at 15:48
  • 1
    @Bohemian I'm confused how were you able to invoke put(); ?? without the variable name preceding it? – jantristanmilan Dec 26 '13 at 21:34
  • 3
    @goldencalf it's an anonymous class, which is an (on-the-fly) subclass*, so `put()` is an instance method, which are implicitly called on `this` - just like you can call `toString()` from any instance method without having to code `this.toString()`. In the example, I've added an overloaded version of `put()` that takes only one parameter and is only visible inside the class definition . – Bohemian Dec 27 '13 at 00:40
  • 3
    Looks like a classic example of code that only the programmer himself is able to read (for a year after he wrote it, until he forgets what the hell he was thinking...) ;) – jackthehipster Jul 09 '14 at 11:58
  • 1
    @jack actually I find these *easier* to read, because they bind the object and its data into a single construct. Separated static initializer blocks are not oviously assiciated with the object being initialized, and can actually result in code that compiles but explodes at runtime. Anyway, it's like most programming idioms; once you get used to them they become second nature. – Bohemian Jul 09 '14 at 21:04
  • Instance initializers like this create a lot of extra methods within your class when compiled, so for resource-sensitive systems like Android, I recommend avoiding them wherever possible. Here's a great talk by Jake Wharton in regards to hidden costs in Java: https://www.youtube.com/watch?v=WALV33rWye4 – lifeson106 Dec 05 '16 at 21:49
  • so, you are creating an anonymous class that extends `HashMap`, and defining the instance initializer for that anonymous class? – scottysseus Dec 15 '16 at 20:01
  • @scott exactly. The overhead is virtually zero, but the code brevity is great. – Bohemian Dec 16 '16 at 10:17
  • @lifeson Jake's talk is not relevant here, because this is a **`static`** inner class, so there are no extra "hidden" methods or references to instances. It has the same (very small) "cost" as a top level class that `extends HashMap` and has an instance block. – Bohemian Dec 16 '16 at 10:26
26

You could indeed put the code at the beginning of every constructor. However, that's precisely the point of an instance initializer: its code is applied to all constructors, which can be handy if you have many constructors and a bit of code that is common to all of them.

(If you're just starting out with programming, you might not have known that it is possible to create many constructors for the same class (as long as they take different parameters); this is known as constructor overloading. If you only have one constructor, then an instance initializer is indeed not very useful (Edit: Unless you abuse it in creative fashions, as illustrated in the other answers).)

Aasmund Eldhuset
  • 37,289
  • 4
  • 68
  • 81
  • In addition, even with a single constructor, declaring and initializing together is more readable and slightly less risky than declaring here and initializing over there. – Andy Thomas Jul 20 '11 at 15:29
7

You can use the instance initializer when declaring an anonymous class, e.g., when perpetrating the Double Brace Initialization Idiom.

List<String> mylist = new ArrayList<String>(){{add("a"); add("b"); add("c");}};

Here you can initialize the object even though you can't add anything to the constructor (because the class is anonymous).

Community
  • 1
  • 1
Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
6

Since all of the code examples here use anonymous classes, I threw together this (slightly horrifying) class that demonstrates using instance initializers in a "proper" class. You can use them to do complex processing or handle exceptions at initialization time. Notice that these blocks are run before the constructor is run, but the constructor is run before initializers in a child class are run:

import java.util.Scanner;

public  class InstanceInitializer {
    int x;
    {
        try {
            System.out.print("Enter a number: ");
            x = Integer.parseInt(new Scanner(System.in).nextLine());
        } catch (NumberFormatException e) {
            x = 0;
        }
    }

    String y;
    {
        System.out.print("Enter a string: ");
        y = new Scanner(System.in).nextLine();
        for(int i = 0; i < 3; i++)
            y += y;
    }

    public InstanceInitializer() {
        System.out.println("The value of x is "+x);
        System.out.println("The value of y is "+y);
    }

    public static class ChildInstanceInitializer extends InstanceInitializer {
        {
            y = "a new value set by the child AFTER construction";
        }
    }

    public static void main(String[] args){
        new InstanceInitializer();
        new InstanceInitializer();
        System.out.println();
        System.out.println(new ChildInstanceInitializer().y);
        // This is essentially the same as:
        System.out.println(new InstanceInitializer(){
            {y = "a new value set by the child AFTER construction";}
        }.y);
    }
}

This outputs (something like):

Enter a number: 1
Enter a string: a
The value of x is 1
The value of y is aaaaaaaa
Enter a number: q
Enter a string: r
The value of x is 0
The value of y is rrrrrrrr

Enter a number: 3
Enter a string: b
The value of x is 3
The value of y is bbbbbbbb
a new value set by the child AFTER construction
Enter a number: s
Enter a string: Hello
The value of x is 0
The value of y is HelloHelloHelloHelloHelloHelloHelloHello 
a new value set by the child AFTER construction

Notice that the "new value" string is not set until after the parent class's constructor has already been called.

dimo414
  • 47,227
  • 18
  • 148
  • 244