Null References: The Billion Dollar Mistake
Tony hoare famously said of his invention of the null reference in 1965;
"This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years"
Today we still suffer much pain from this, with Java's infamous NullPointerException being one of the most frustrating avoidable errors that can occur, almost always as a result of programmer error. So we have to ask ourselves, why are we still suffering so much?
Neither Type Safe nor Object Orientated
The concept that you can return a null pointer from a method call seems to go against the concept of both the Object Orientation Paradigm and a secure Type System. For example if a method declares a return type of Map the type system will allow you to return a HashMap, but if you try to return a List it would cause a compiler error. On an object that is returned you expect to be able to call a method declared on Map, such as Map#put, this is valid with HashMap as it extends Map but not on List. The question then arises why it is acceptable to return null because when you try to call null#put you get the dreaded NullPointerException.
Once you allow null pointers into your code, very much like a virus, they quickly infect your whole system. The symptoms that are exhibited are excessive null pointer checks and error stack traces containing NullPointerExceptions. You find your code starts to get very ugly as you have to insert null checks not only at the place that the null occurs but everywhere, quiet often just out of the fear of what might be that can grip a developer.
The Null Object Pattern
The first solution to consider is the Null Pointer Pattern, where an object with neutral behaviour can be created and returned instead of null. While, if possible, this is probably the best way to deal with the problem it is not sufficient to deal with all the possible use cases we come across, for example finding a value in a list, so we need something else to add to our tool box.
Annotating the problem
There are annotations around that can be used to assist in reducing the chances of null pointer exceptions, most notably Intellij's @NotNull and @Nullable, which allow static analysis of the code to help sugest places where problems could arise.
Maybe an Answer?
If the type system could enforce the handling of nulls at source you could happily code elsewhere without any chance of a null creeping in. Other programming languages have solutions to this problem, with one of these being the Maybe type in Haskell. From the Haskell documentation on Maybe;
The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.The Java implementation, for which you can find GitHub details below, consists of the Maybe interface and two concrete classes Just, which wraps the object being returned, and Nothing, which represents the absence of an object.
So what would its usage look like? A couple of such examples are here.
In this example the method declaration clearly tells the client code that the method may not return an object of type Bar, but it will return an Object of type Maybe. The Maybe construct also allows the type system to enforce that Foo#doSomething does not then pass through the possible null it may otherwise have done. This also displays a convenience method which allows you to get the contained object or return a default value instead, in this case an implementation of the Null Object pattern,
The following shows the same example but this time allowing the method to return null. This shows how the null checks can make the code less concise or how a null reference can be mistakenly either returned to the calling client or passed onto another method.
Where Are Null Checks Still Acceptable?
At the boundaries between your code and third party libraries, such as the Java collections, as well as for external inputs to your system. I would not even use it for lazy initialization rather again make it explicit that this value may not be set, there are many times I have seen a field set in the getter method only for it to be accessed at a later time from another method directly assuming it was set.
Full Java Implementation of Maybe
The full Java implementation of Maybe can be found on my GitHub page.https://github.com/leneghan/maybe
You can also find an implementation in Googles guava library called Optional.http://docs.guava-libraries ... /Optional.html
Post a Comment