Java Coding Notes
Notes on Java, the JVM and writing software that lasts

Optional is a return type, not a field type

· by Serguey Asael Shinder / Serguey Shinder

Optional was added to express one thing: this method may legitimately have no answer. It has since been used for four other things, and three of them are worse than the null they replaced.

Where it belongs

A method whose absence of result is a normal outcome, not an error.

Optional<Account> findByEmail(String email);

The caller cannot ignore the possibility. That is the entire value.

Where it does not

As a field. private Optional<String> middleName; costs an extra object per instance, is not serializable, and moves the null one level down rather than removing it — the field itself can be null. Use a nullable field and document it.

As a parameter. A method taking Optional<X> now has three input states: present, empty, and null. That is worse than two. Overload the method instead.

In collections. List<Optional<String>> is a list where absence is already expressible by not putting the element in.

The call that undoes the point

opt.get()

If you call get() without isPresent(), you have written a NullPointerException with extra steps and a longer name. The methods that make Optional worth having are the ones that keep you inside it:

findByEmail(email)
    .map(Account::id)
    .filter(id -> id > 0)
    .orElseThrow(() -> new AccountNotFound(email));

The honest cost

Every Optional is an allocation. In a hot loop that matters and the profiler will say so. Outside a hot loop it does not, and the clarity is worth more than the object. Know which one you are in before optimising it away.

Applies to Java 8 and later.