In 2009, Tony Hoare apologized for his billion dollar mistake: introducing the null reference to ALGOL W in 1965. He argues that null reference violations and crashing software must have cost businesses an amount of money in the order of a billion dollars due to missed revenue, time wasted and other side effects.

It is canonically understood that his introduction trickled down to newer languages (such as Java and .NET), meaning that design choices of these programming languages also allow null references and no void safety. In Java the following example will compile and produce the well-known NullPointerException at runtime:

final String someString = null;
someString.length();

Java never introduced a first-class language construct which can fully avoid null references. Many third-party solutions exist, such as the wild variety of @NonNull - or @NotNull depending on who you ask - implementations and the various supporting toolsets such as in IntelliJ or that of SpotBugs. This is in stark contrast with for example Kotlin which has (with limitations) null safety built in as a language design choice.

Even the introduction of Optional in Java 8, which has some resemblance of a null-restricted concept, was arguably a botched attempt at null safety as it still allows to be initialized as null. Meaning that this:

public Optional<T> getSomething() {
    return null; // for whatever reason!
}

is madness but will also compile and produce a NullPointerException when a caller assumes they can immediately check the Optional for emptiness. A change might be underway for future versions of Java.

Welcome to Valhalla

Project Valhalla is an experimental "playground" for OpenJDK which aims to land new language features in Java focusing on value objects, user defined primitives, value classes for basic primitives and enhanced generics to support value classes. Many words have already been written about these intended changes and if you want to take a deep dive, I suggest to read through the JEP's and background materials listed on the project overview page.

The reason why the title of this post contains "might eventually", is because those JEP's are still marked as draft and have been for many years. Some proposed changes of project Valhalla have already started to land in upstream Java releases and others have been reworked, rebranded and rewritten. Take all the information in this post with a grain of salt as it's based on information scrambled together from the current JEP's and mailing lists and might change faster than this post can be updated!

Value objects & implicit value object creation

JEP 401 aims to introduce implicit value object creation. It builds upon another JEP draft for value objects which can be summarized as immutable class instances which lack identity. A value object is different from a record (introduced in Java 14): a record has an identity and could be considered boilerplate-less immutable data objects with transparent state:

record Position(int x, int y) {}
final Position posA = new Position(10, 20);
final Position posB = new Position(10, 20);
assert posA.equals(posB);
assert posA != posB; // different references so not equal!

A value object will result in a completely new implementation which allows you to drop object identity and get close to the performance of primitive types. A value object - like a primitive - doesn't hold a reference to an object but holds the value directly in memory. A value object will be equal using value comparison (x == y) if all fields of that value object are equal. And a record is a suitable value!

value record Position(int x, int y) {}
final Position posA = new Position(10, 20);
final Position posB = new Position(10, 20);
assert posA.equals(posB);
assert posA == posB; // value objects are equal!

The interesting part is that value objects in combination with implicit value object creation allow value objects to never be null. By adding an empty constructor which is marked as implicit, this constructor will be used to create a default non-null variety of the value object at runtime:

value record Position(int x, int y) {
    public implicit Position();
}

This will give Position a default value object, with fields set to the respective implicit value of those fields:

final Position posA = Position.default;
assert posA.x() == 0;
assert posA.y() == 0;

Note that the use of the implicit keyword to enable implicit value object creation is still not final due to the nature of a JEP draft. If you are curious, discussions in the Valhalla mailing list also consider using default or even default constructible which might look something like this:

value record Position(int x, int y) {
    public default constructible Position();
}

Null-restricted type

JEP 401 also discusses a "null-restricted type" but sadly at the moment of writing the referenced JEP for null-restricted types still has number 404 (not found). It is not yet available to the general public but the gist of it is clearly defined:

The most relevant feature for this JEP is that the type of a variable or method return may use a ! suffix to indicate that it does not store null. This is enforced with runtime checks.

Note that the syntax used is a small detail and the actual implementation is where the difficulties lie. We will quickly gloss over how this could work in practice but theoretically a null-restricted type will have a big impact of which the details are not yet known.

Practically, for our previously defined Position value class with implicit value object creation, this will eventually be possible:

class Player {
    private Position! position; // position is marked as null-restricted
    
    public Player() {
    }
    
    public Player(Point! position) { // parameter also marked as null-restricted
        this.position = position;
    }
    
    public Position! getPosition() { // null-restricted return type
        return this.position;
    }
}

Due to the exclamation mark and the implicit definition of Position, we can safely guarantee that Player.position will never be null even if it's not explicitly assigned:

Player player = new Player(); // default constructor, not setting position
assert player.getPosition() == Position.default; // yet position is value-equal to the default!
assert player.getPosition().x() == 0;
player = new Player(null); // NullPointerException (and can probably be caught compile-time?)

Primitives will become value objects

Project Valhalla also aims to rework the current primitive system (JEP 402) by migrating them to value objects. Boxing and unboxing will become implicit because each primitive will be backed by the functionality of the corresponding value class. Whereas now you have to do this:

long someLong = 777L;
int someInt = Long.valueOf(someLong).intValue(); // or (Long) someLong

After the migration of primitive types to value objects is complete, you can call any method of the value class on primitives directly:

long someLong = 777L;
int someInt = someLong.intValue();
int longHashcode = someLong.hashCode();

Under the hood, primitives such as int and double will be using their respective value class. This will also enable them to be null-restricted types because they will have an implicit value object as described above.

Some pre-work has already landed in upstream Java (16+), signaling that not only primitives but also other standard JDK classes are value-based and will eventually migrate to become value objects. Including but not limited to  Optional. Meaning that in a distant future you might be able to use this interface:

// note the exclamation mark!
public Optional<T>! getSomething();
public Integer! getAnInt();

Which will have a runtime guarantee that the return value will never be null but instead the value created by implicit value object creation. For an Optional, my assumption is that this will be an empty Optional.  The primitive value objects speak for themselves; int = 0, bool = false and so forth.

Conclusion

Will null references in Java be a thing of the past? No. Simply due to backwards incompatibility it's unlikely this will ever happen. What Valhalla will eventually bring is highly performant value objects which can be null-restricted. We have a rough idea how it will work and look but it's still subject to change. Project Valhalla is being heavily worked on indicated by the many JEP's, some of which are still not public.

As these features bring core changes to the language specification and primitive system, they will not be finished next week or month. Probably in the order of "next few years" with many early-access releases, reconsiderations and improvements in-between to eventually land in a future Java release.

Want more content like this?

Hi! I sporadically write about tech & business. If you want an email when something new comes out, feel free to subscribe. It's free and I hate spam as much as you do.

your@email.com Subscribe

Java might eventually get null-restricted types