37

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?

5
  • it wouldn't be a big deal if java rids of this feature. Commented Jul 20, 2011 at 14:36
  • 10
    @irreputable, it's seldom that I need them, but anonymous classes can't have constructors, but they can have instance initializers, so we need it in the language. Commented Jul 20, 2011 at 14:42
  • 1
    @Kaj field initializers can do the job Commented Jul 20, 2011 at 23:27
  • 2
    @irreputable, Only if you need to assign a value to a field, not if you need to invoke methods. Commented Jul 21, 2011 at 10:38
  • @Kaj: Anything that can be done with an instance initializer can be done without it, even in an anonymous class. Just replace int foo; { ...; foo = resultOfComputation; } with int foo = f(); private int f() { ...; return resultOfComputation; }. If you need a side effect not related to setting a field, you could use private int dummy = (beep(), 0);. (Though I don't see why constructors for anonymous classes could not be added to the language.) Commented Apr 30, 2024 at 0:34

4 Answers 4

44

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);
    }
};
Sign up to request clarification or add additional context in comments.

9 Comments

For people using instance initializers for collection population, look to the Guava Library as a more elegant and powerful alternative. The Maps class provides nice Map utilities and their Immutable* classes are particularly nice for the use case described here, see ImmutableMap.
@Bohemian I'm confused how were you able to invoke put(); ?? without the variable name preceding it?
@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 .
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...) ;)
@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.
|
29

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

1 Comment

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

1 Comment

In this particular case, though, I would recommend using java.util.Arrays.<T>asList(T... ts) instead :-)
7

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.