Another Java technology blog from a developer far away from home

The Guava’s aficionado have been dealing with the concept of Optional for a while (since Guava 10 actually, it’s been 3 years). As usual, I’m not going to talk about how to use Optional, I’m more interested in the way Google implemented the concept, the Java 8 implementation and the differences between the two of them.

It took two years and a half to feel this gap in the JDK, and the choices made by the JDK expert groups are interesting in terms of implementation but also naming convention.

But let’s start with the Guava implementation.

Guava

Optional is an abstract class, implementing Serializable. It might look like a small detail, but it’s not, I’ll come back to this point while talking about the Java 8 implementation.

The Guava team decided to split the concept of the Optional, being empty or not, by creating two different implementation: Absent and Present.

These classes are not accessible directly, the default constructor of Optional has been restricted to the package, the underlying implementations don’t offer any public constructors, they just inherit the one from Optional which is not accessible, and to enforce this, the classes Absent and Present are only visible at the package level:

The of(T reference) method will always return a Present object, if the parameter is null, a NullPointerException will be thrown.

The fromNullable will return an Absent object if the parameter is null, otherwise Present. Nothing fancy so far, the interesting part relies in this separation between Absent and Present.

By definition, Optional is an immutable object, considering this, there is no reason for the method isPresent() to check every time if the value in the Optional is null or not, because between two calls it can’t change.

So, once an Absent object has been built, it will always represent an absence of value, the implementation of the methods get() or isPresent() becomes very straightforward:

We might think it’s a matter of optimisation, but today the JVM would optimise an implementation like this:

public boolean isPresent() {
return value != null;
}

The value being final, modern JVMs can easily optimize this kind of code with method inlining and JIT compilation. So in the end, it’s more a separation of concept than a real optimisation.

There is only one instance of Absence object per JVM (static field of Absence instantiated when the class is loaded). Optional always use this instance when an Optional is created from a null reference. That means it doesn’t matter if you represent an Optional<String> or Optional<Integer>, if your Optional is empty, both variable will point to the same instance.

The implementation of Present follows the same pattern, immutability offers a straightforward path, the value will never be null:

Like any other Java Object, Optional offers hashCode and equals method. The hashCode is interesting, the Absence object always return the same magic constant: 0x598df91c, but, for Present, the formula is a combination of this magic constant and the hashCode of the value:

The interesting part lies in the interaction you can get from the JDK’s Optional with functional programming paradigm. Just like the Guava one, it offers the methods or(Supplier<? extends T> supplier) (it’s actually orElseGet in the JDK) and transform (map in the JDK). But the JDK goes further with filter and flatMap:

Predicate and Function are new functional interfaces introduced in Java 8, but these interfaces have been available in Guava since the beginning (version 2.0 actually), I’m surprised they don’t provide filter and flatMap. Even the transform method took 8 months to be introduced in Guava after they released the Optional feature. You might say, the difference between flapMap and map is very small, it’s just about the mapper returning an Optional directly, but still it doesn’t cost anything in terms of implementation and maintenance.

Regarding the hashCode, they took a different direction. They don’t separate the concept of the value wrapped in a container and the value itself, they rely directly on the hashCode of the value:

@Override public int hashCode() {
return Objects.hashCode(value);
}

That means if the Optional is empty (value == null), 0 will be returned, otherwise the hashCode of the value directly.

Serializable

The main difference between the Java 8 and the Guava implementation (beside the functional programming orientation of the Java 8 with map, flatMap and filter) is the decision of the Java expert group to not make Optional serializable (contrary to the Guava one). This decision initiated intense debates other the internet. That means, if you’re using serialization and Guava Optional, the migration to the JDK’s Optional will break your serialization system with a nice java.io.NotSerializableException.

Why this decision ? So far I can see two answers: one from a technical/maintenance point of view and the other one from a concept point of view (the way they think Optional should be use).

During the elaboration of the JSR-335 (Lambda expression, Stream, Optional bound…), someone came up with the name OptionalReturn to enforce the design orientation of the feature. Yes, they considered that Optional should not be any more than a support the optional-return idiom only. It wasn’t meant to be used as a field for classes. This is why Optional hasn’t been marked with Serializable in terms of design/concept point of view. However, even if you decide to use Optional, only in the context of optional-return pattern, your methods could not be used through RMI.

About the technical reason, I will let Brian Goetz (Java language architect at Oracle) give the explanation itself. If someone knows better than us, that’s probably him, here is his quote from a mailing discussion:

Making something in the JDK serializable makes a dramatic increase in our maintenance costs, because it means that the representation is frozen for all time. This constrains our ability to evolve implementations in the future, and the number of cases where we are unable to easily fix a bug or provide an enhancement, which would otherwise be simple, is enormous.

Beside of the functional programming orientation, I think Optional are all about improving readability and enforcing public interface contracts. When you’re dealing with private class fields, it’s up to you to manage what’s happening behind the scene. It’s not necessarily a bad practice to use it as class field, but a pattern like this wouldn’t be wrong neither and at least still serializable:

I was wondering if there is any (really) under-the-hood performance reasons for choosing one implementation over the other. At a first glance doesn’t seem like it but I find the Guava implementation so much clearer and neater that I keep thinking there must be a reason why JDK architects chose to go down other path…

I like the Guava implementation too, but now that Java has a standard implementation, we prefer using standard classes in our projects. Regarding performances, I’ve never run any benchmark on it, but I would be surprised if there was any significant difference between the two.