Optional<T> tends to be used in a wrong way

  |   Source

Want to explicitly declare a nullability contract? You probably might want to use Optional<T>, but it does not seem to be the best way. I've got some cons against it.

The cons

It's just another object created to enclose a nullable value

Hit the heap?

Iterables of Optionals are more expensive than Iterables of "regular" objects

This one is derived from the latter point.

It still requires checking for isPresent

... and thus bringing nullability checks to runtime, otherwise it fails with NoSuchElementException. How much does it differ from NullPointerException? Is it disguisted?

Standard functional interfaces like Consumer, Supplier, and Function in Java 8 are not checked-exceptions friendly

Sad truth for those who prefer ifPresent.

Optional<T> may lack support by (de)serialization libraries

Unless they're updated either by you or by the maintainers of the libraries. Moreover, Optional is not Serializable. Have fun.

Optional.class can't say anything of the parameterization

The Google Guava and Google Gson TypeToken and the Spring Framework ParameterizedTypeReference can help in some use cases. Some frameworks and libraries can only spot fields by classes or primitites types, but not generics what Optional<T> is.

What if use emptyList()/singletonList(T) as a surrogate Optional<T>?

Seriously, why not? Semantically these two really does not differ much from Optional however having another methods exposed. !isEmpty just stands for isPresent.

Optional<T> only means the can be no value

It's a clear implementation of the Null Object pattern. Null objects are not nulls and have some default null object behavior whilst null cannot have any behavior.

Optional<T> can be null itself and you can't ever avoid it

Nuff said.

What's then?

Use JSR-305 @Nullable and @Nonnull wisely.

Interface methods return values

Bad:

public interface IService {

    String getId();

    String getName();

}

Good:

public interface IService {

    @Nonnull
    String getId();

    @Nullable
    String getName();

}

The interface method return value types are more aligned now, right?

Another case

Bad:

public static Optional<String> foo() {
    ...
}

Good:

@Nullable
public static String foo() {
    ...
}

Now you can do whatever you want: either check it for null or wrap it in an Optional.ofNullable if you really like it. Don't let the code force you to follow excessive "conventions".

Class fields

Bad:

public final class Box<T> {

    private final Optional<T> value;

    ...

    public Optional<T> getValue() {
        return value;
    }

}

Good:

public final class Box<T> {

    @Nullable
    private final T value;

    ...

    @Nullable
    public T getValue() {
        return value;
    }

}

Just no fields bloating.

Method arguments

Bad:

public static void foo(final Optional<String> value) {
    ...
}

Good:

public static void foo(@Nullable final String value) {
    ...
}

Yes, I know, some Optional-oriented folks may say they don't use Optional as method parameters. Why not aligning to returned values? Another point for the latter piece of code is that the foo method does not force you to pass an Optional to it, and it can wrap it up when it needs it on its own.

As the very end

And don't trust Uses for Optional much.

You might also like to read a more detailed article Nothing is better than the Optional type by Michael Ernst.

Comments powered by Disqus