There are two kinds of programmers out there. Those that have had null-related errors in their programs and those that are just starting their careers. The dreaded null, nil, undefined… Most programming languages have a concept for “nothing”. But what is nothing? Have you ever thought about null, what is it really? And what is it not? Let’s see what null means in Java.
To get things started, null in Java is not an instance of any type. Java’s type comparison operator, instanceof, is defined as follows:
At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast to the ReferenceType without raising a ClassCastException. Otherwise the result is false.
So by definition null is not an instance of anything.
However, the Java Language Specification, or JLS, defines a special null type. The null type has no name, and as such you can’t declare a variable of the null type. You can’t cast anything to the null type either. The only possible value ever to exist (or not?) for null type is the null reference itself. For every other reference type, you can always assign the value as null. As JLS states:
The programmer can ignore the null type and just pretend that null is merely a special literal that can be of any reference type.
In Java, null equals null. Meaning “null == null”. Also, by contract, the equals method from java.lang.Object states that for any non-null reference “ref” of type TYPE, ref.equals(null) should return false. So while null equals null, it is not equal to anything else.
How do you use null then? Propably the most common use-case is to denote the fact that the reference requested does not exist or is unavailable. For instance, Java’s System.console() method returns null, if no console is available.
Null is also the default value for all reference variables. This means that for every reference variable, if you won’t assign a value, it’ll be null. This fact can be used, among other things, to implement lazy initialization of your fields, where you populate the possibly expensive fields only when you need them for the first time. In cases like these null is used to represent an uninitialized state.
In addition to referring to non-existing object or uninitialized state, general use-cases for null include signifying termination condition (see BufferedReader.readLine();) and having an unknown value (like mapping null to certain key in a Map).
Sir Tony Hoare has famously stated that inventing null has been his billion dollar mistake. There are ways to work around the concept of nullability, for instance using Null object pattern. Whatever you decide to do, be mindful of your code when it's even remotely possible that a reference could be null. Otherwise your app might just
Exception in thread "main" java.lang.NullPointerException at to.dev.WhatIsNull.main(WhatIsNull.java:42)
Top comments (9)
Nice. Would be great to See some alternatives though :)
Do you mean comparison between how nulls work between different languages or more about the null object pattern? Well, maybe someday :)
I mean for example the Option/Optional type as in Rust or Java. Also, Kotlin has an interesting null approach :)
Indeed, after I posted this I realised that I had left out the Optional class and how to use it. Although when talking about null, I think it would've been a footnote like mentioning the null object pattern was. Those things could be worthy of a blog post of their own, don't you think?
Haha, if you don't hurry I may be tempted to write something about null alternatives myself :)
Great post, Lauri!
This is one of those titles that you think to yourself "damn, why didn't I think about it before?!"
I must admit that I did Google it to see if anyone had used it before, and sadly I wasn't the first :)