views:

113

answers:

3

(For the purposes of this question, let us assume that one is intentionally not using auto(un)boxing, either because one is writing pre-Java 1.5 code, or because one feels that autounboxing makes it too easy to create NullPointerExceptions.)

Take Boolean, for example. The documentation for the Boolean(boolean) constructor says:

Note: It is rarely appropriate to use this constructor. Unless a new instance is required, the static factory valueOf(boolean) is generally a better choice. It is likely to yield significantly better space and time performance.

My question is, why would you ever want to get a new instance in the first place? It seems like things would be simpler if constructors like that were private. For example, if they were, you could write this with no danger (even if myBoolean were null):

if (myBoolean == Boolean.TRUE)

It'd be safe because all true Booleans would be references to Boolean.TRUE and all false Booleans would be references to Boolean.FALSE. But because the constructors are public, someone may have used them, which means that you have to write this instead:

if (Boolean.TRUE.equals(myBoolean))

But where it really gets bad is when you want to check two Booleans for equality. Something like this:

if (myBooleanA == myBooleanB)

...becomes this:

if (
    myBooleanA == myBooleanB ||
    (myBooleanA != null && myBooleanA.equals(myBooleanB))
)

I can't think of any reason to have separate instances of these objects which is more compelling than not having to do the nonsense above. What say you?

+5  A: 

The cached values are never garbage collected, so use the constructors whenever you'd like to use them as soft/weak references, so that it can be garbage collected anyway whenever needed. The same applies on Long#valueOf(), Integer#valueOf() and consorts with values within cacheable ranges.

Doing a reference search in Eclipse learns me that under each java.lang.Thread uses new Boolean() as a soft-reference based cache, it's even explicitly commented (in isCCLOverridden() method):

/*
 * Note: only new Boolean instances (i.e., not Boolean.TRUE or
 * Boolean.FALSE) must be used as cache values, otherwise cache
 * entry will pin associated class.
 */
BalusC
A: 

These object types were needed because the Collection class only accepted objects, hence you couldn't use the native types.

This introduced the design flaw you are talking about and hence autoboxing was introduced.

EDIT

And the constructors are public because they were always public. Before the world of autoboxing in some very poor code you wanted new Integer(0) != new Integer(0) to be true. It was a flaw more than anything of the original design, however since its a part of the public interface now they don't want to break old code.

I bet they could deprecate it now and most people would be ok with it since autoboxing just works.

Pyrolistical
+1  A: 

The constructors are public because of backwards compatibility... .valueOf() only got added in java 1.4...

Also using a Boolean as a tri-state variable in your example (null/TRUE/FALSE) is probably a bad idea -- better to use an enum (UNKNOWN,TRUE,FALSE), or if null is not a valid value, check for it, and manually unbox for testing equality.

CuriousPanda
Regarding using Booleans as tri-states: I agree, enums are preferable, but this is more of a defensive programming thing; i.e. handling the case where someone hands you a null when you were expecting only TRUE or FALSE. (This is the exact reason why I feel that autounboxing is dangerous; it makes it too easy to ignore the null case when you are treating Objects like primitives.)
Robert J. Walker