Sunday October 15, 2006 (See intro for a background and caveats on these coding advice blog entries.)
If you've been coding in C, you've probably picked up the habit of initializing all your fields:
char *foo = NULL;
int bar = 0;
This is necessary, because in C, memory can be left uninitialized, so there's no telling what value foo will have before it is assigned something.
In Java, however, the language specification clearly defines default values, so virtual machines will for example always initialize reference fields to null.
Specifically, this means that code like the following is redundant:
private int foo = 0;
private Bar bar = null;
private boolean baz = false;
The alternative form of initializing the fields explicitly in the constructor, is the same:
private int foo;
private Bar bar;
private boolean baz;
public Foo() {
foo = 0;
Bar bar = null;
baz = false;
}
You can leave out the above initializations, and the program will behave the same way. Carl Quinn once convinced me that this was more readable, so I picked up the habit, and I now swear by it. On the one hand, you can argue that leaving the explicit initializations in is more readable because you're making it really clear what it is you are intending. On the other hand, Java programmers quickly learn what the default values are and understand that an uninitialized field is the same as a nulled out field.
It turns out that the two forms are not exactly identical! If you disassemble the above code, you'll find the following bytecode is generated:
4: aload_0 5: iconst_0 6: putfield #2; //Field foo:I 9: aload_0 10: aconst_null 11: putfield #3; //Field bar:LBar; 14: aload_0 15: iconst_0 16: putfield #4; //Field baz:Z
If you leave out the initializations, none of the above bytecode is generated. In a simple microbenchmark there was a measurable time difference (about 10%) for the case where a handful of fields were initialized versus leaving them uninitialized, so it's clear that Hotspot doesn't completely eradicate the differences here. (<speculation>Perhaps it just zeroes out the whole object memory block when allocating a new object, relying on the default values to all be represented as zeroes natively, and this is done even when all fields are later initialized?</speculation>)
Obviously, speed considerations is not what should be the deciding factor here. This was a microbenchmark doing nothing other than construct objects with and without initialization - it's unlikely that you'll find a measurable difference on a real program. What really matters is readability. I should also point out that Findbugs will treat these two scenarios differently. If you print out a field value in the constructor, it will warn about an uninitialized field if the field was not explicitly initialized in the field declaration.
I can see arguments both for and against explicit field initialization, but I think this is one of those cases where convention wins. I personally find code cleaner and more readable when you leave your fields with implicit rather than explicit initialization.
P.S. Remember that null fields are often a bad idea and should be initialized to null-objects!
(2006-10-15 17:38:45.0) Permalink Comments [4]
Posted by Kasper Nielsen on October 16, 2006 at 02:18 AM PDT #
There is a difference between behaviour of assigning or not assigning fields. If the superconstructor calls any methods of the subclass, changes to the fields will be overwritten. Even the Object constructor can be replaced with the instrumentation API. Not that you'd want to do that, but the JVM and javac need to implement it correctly.
There is also the problem of unsafe publication which could theoretically result in the assignments running after other methods are called on the object. (I have no idea how to do this in practice.)
Posted by Tom Hawtin on October 16, 2006 at 04:04 AM PDT #
Posted by Marc on October 16, 2006 at 04:49 AM PDT #
Posted by Casper on October 16, 2006 at 05:06 AM PDT #