Sometimes, programmers who are new Java will use primitive types and wrappers interchangeably. This can lead to problems. Consider this example:
public class MyRecord {
public int a, b;
public Integer c, d;
}
...
MyRecord record = new MyRecord();
record.a = 1; // OK
record.b = record.b + 1; // OK
record.c = 1; // OK
record.d = record.d + 1; // throws a NullPointerException
Our MyRecord
class1 relies on default initialization to initialize the values on its fields. Thus, when we new
a record, the a
and b
fields will be set to zero, and the c
and d
fields will be set to null
.
When we try to use the default initialized fields, we see that the int
fields works all of the time, but the Integer
fields work in some cases and not others. Specifically, in the case that fails (with d
), what happens is that the expression on the right-hand side attempts to unbox a null
reference, and that is what causes the NullPointerException
to be thrown.
There are a couple of ways to look at this:
If the fields c
and d
need to be primitive wrappers, then either we should not be relying on default initialization, or we should be testing for null
. For former is the correct approach unless there is a definite meaning for the fields in the null
state.
If the fields don't need to be primitive wrappers, then it is a mistake to make them primitive wrappers. In addition to this problem, the primitive wrappers have extra overheads relative to primitive types.
The lesson here is to not use primitive wrapper types unless you really need to.
1 - This class is not an example of good coding practice. For instance, a well-designed class would not have public fields. However, that is not the point of this example.