null does not mean false

A special value is used as marker when a pointer does not refer to a valid object, Java calls it "null", but you could have seen the concept thing called NULL, nullptr, NIL, nil, undefined, ..., in other programming languages.

The general sense of null (or whatever is its actual name in a specific language) is clear, but there are many subtleties on which there is no common consensus.

For instance, there are languages where null is considered as a synonym of the false boolean value, but this is not true for Java. And if you forget it, you could have some unpleasant surprise.

Let’s think to a simple method that just write a message if the passed parameter is a (primitive) boolean true.
public void test(boolean value) {
    if (value) {
        System.out.println("The value is set to true");
    }
}
Not an impressive piece of code, but at least it does what anyone would expect.

Here, the passed parameter is a primitive boolean variable, and Java primitive variable are not instance of classes but mere memory objects. They resolve to rough memory location, no pointers involved. So in a boolean variable we could store just a true or a false value.

Things are getting tougher if we apply a tiny "improvement" to our method:
public void badTest(Boolean value) {
    if (value) { // !!! fishing for troubles !!!
        System.out.println("The boolean is set to true");
    }
}
Now our class is accepting a Boolean (uppercase!) variable as parameter. That means a real object in the Object-Oriented sense of the word so, being here in the Java world, a pointer to an instance of a full-fledged class, or null.

The trouble is all in the last sentence tag: "or null". And null in Java is just an invalid reference, no implicit conversion to false, as it happens in other languages.

What happens if we call our method in this way?
bt.test(null);
The virtual machine would try to dereference the pointer to a Boolean, find out that it is actually impossible, and would pass back this valuable information to the caller in form of an exception. One would argue that any Java method should declare any exception that could be thrown in its body, and wonder why this is not happening here. Well, the fact is there is a family of Exceptions, with root in RuntimeException (an Exception extension) and all its derived classes, that are considered "normal", in the sense they could happen anywhere and so are not required to be declared. Null pointer dereferencing, division by zero, and other calamities like that, are in this category.

The end of the story is, if we really need a Boolean, we should ensure that it is correctly set before using it:
public void testA(Boolean value) {
    if(value == null) {
        System.out.println("null is not false nor true");
        return;
    }

    if (value) {
        System.out.println("The boolean is set to true");
    }
}
Or, be prepared to manage a null pointer exception:
public void test(Boolean value) {
    try {
        if (value) {
            System.out.println("The value is set to true");
        }
    } catch (NullPointerException npe) {
        System.out.println("null is not false nor true");
    }
}
As often happens there is no generically better approach. In this case, I reckon it would be better to use the first way - explicit check of the pointer - if we actually expect null as a valid input value. On the contrary, if the would have expected the Boolean to be correctly set, and a null it is a sign of something wrong happened before, it could make more sense the try-catch solution.

No comments:

Post a Comment