variables - Why java Instance initializers?



blocks of (5)

This question already has an answer here:

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?


Answers

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


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

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.


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


IMHO the pervasive, implicit localization in Java is its single largest design flaw. It may be intended for user interfaces, but frankly, who really uses Java for user interfaces today except for some IDEs where you can basically ignore localization because programmers aren't exactly the target audience for it. You can fix it (especially on Linux servers) by:

  • export LC_ALL=C TZ=UTC
  • set your system clock to UTC
  • never use localized implementations unless absolutely necessary (ie for display only)

To the Java Community Process members I recommend:

  • make localized methods not the default, but require the user to explicitly request localization.
  • use UTF-8/UTC as the FIXED default instead because that's simply the default today. There is no reason to do something else, except if you want to produce threads like this.

I mean, come on, aren't global static variables an anti-OO pattern? Nothing else is those pervasive defaults given by some rudimentary environment variables.......





java