Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Static initialization

Tags:

java

static

can you explain me which is the difference between:

public class Test {

    public static final Person p;

    static {
        p = new Person();
        p.setName("Josh");
    }

}

and

public class Test {

    public static final Person p = initPerson();

    private static Person initPerson() {
        Person p = new Person();
        p.setName("Josh");
        return p;
    }

}

I have always used the second one, but is there any difference with an static initializer block?

like image 394
Héctor Avatar asked Feb 12 '15 08:02

Héctor


1 Answers

There are of course technical differences (you could invoke the static method multiple times within your class if you wanted, you could invoke it via reflection, etc) but, assuming you don't do any of that trickery, you're right -- the two approaches are effectively identical.

I also prefer the method-based approach, since it gives a nice name to the block of code. But it's almost entirely a stylistic approach.

As Marko points out, the method-based approach also serves to separate the two concerns of creating the Person, and assigning it to the static variable. With the static block, those two things are combined, which can hurt readability if the block is non-trivial. But with the method approach, the method is responsible solely for creating the object, and the static variable's initializion is responsible solely for taking that method's result and assigning it to the variable.

Taking this a bit further: if I have two static fields, and one depends on the other, then I'll declare two methods, and have the second method take the first variable as an explicit argument. I like to keep my static initialization methods entirely free of state, which makes it much easier to reason about which one should happen when (and what variables it assumes have already been created).

So, something like:

public class Test {
    public static final Person p = initPerson();
    public static final String pAddress = lookupAddress(p);

    /* implementations of initPerson and lookupAddress omitted */
}

It's very clear from looking at that, that (a) you don't need pAddress to initialize p, and (b) you do need p to initialize lookupAddress. In fact, the compiler would give you a compilation error ("illegal forward reference") if you tried them in reverse order and your static fields were non-final:

public static String pAddress = lookupAddress(p); // ERROR
public static Person p = initPerson();

You would lose that clarity and safety with static blocks. This compiles just fine:

static {
    pAddress = p.findAddressSomehow();
    p = new Person();
}

... but it'll fail at run time, since at p.findAddressSomehow(), p has its default value of null.

like image 94
yshavit Avatar answered Nov 15 '22 04:11

yshavit