Code Advice #14: Don't initialize fields to default values

(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!

Comments:

I think most vm's rely on the GC to zero out memory. Much faster then doing it for every object at allocation time.

Posted by Kasper Nielsen on October 15, 2006 at 07:18 PM 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 15, 2006 at 09:04 PM PDT #

I believe the difference between the generated bytecodes should be considered as an optimization bug, and should not be taken into account when choosing a best practice.

Posted by Marc on October 15, 2006 at 09:49 PM PDT #

I am a practitioner or explicit initialization, even for non-lazy singletons (via static code block) because I find that by requiring such initializations I do not overlook cases where the default is NOT what is needed. The issue is subtle and I can understand both practices. There are much worse things along these lines, e.g. new'ing up a String instance after the field decleration. Then again, String is a weirdo.

Posted by Casper on October 15, 2006 at 10:06 PM PDT #

Post a Comment:
Comments are closed for this entry.
About

Tor Norbye

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today