Jhonny007 Jhonny007 - 1 month ago 11
Java Question

Use of Optional in a map

Ok before I start explaining my question I want you to know that I know about the design idea behind

Optional
and that it isn't intended to be used in fields or collections, but I have programmed a lot in Kotlin currently and really dislike using
null
.

So I have a Node based editor like in the Unreal Engine and each node has
ConnectionBox
es, which can be either free or are occupied by a
Connection
.

So there are different ways to express this one of which is using a map that maps each
ConnectionBox
to a
Connection
like:

Map<ConnectionBox, Connection> connectionEndPoints;


and
Connection
could be
null
if the
ConnectionBox
is free. I don't like this, since an other developer doesn't know about the function of this Map and that it may return
null
for an existing
ConnectionBox
.

So I am tempted to use a:

Map<ConnectionBox, Optional<Connection>> connectionEndPoints;


which displays the intend much better and you can even read it like:

"This
ConnectionBox
may have a
Connection
attached."


My question is: Why should I not do this, even though it shows the intend much more clearly and prevents
NPE
s. Every SO-thread and every blog post says this is bad style and even the compiler say that I shouldn't do it with a warning.




On request here is a SO-thread that discourages use of
Optional
as a field or Collection value: Uses for Optional

And here is the warning (as it turns out it is a warning from IntelliJ):

Warning: Optional used as type for field {fieldName}




Ok after recommending that the
Connection
reference should lie within the
ConnectioBox
the question just shifts.

Why is:

class ConnectionBox {
Optional<Connection> connection;
...


worse than

class ConnectionBox {
Connection connection; //may be null
...


Unless I make a comment you can't see that you may run into a
NPE
and I dislike comments explaining code that could explain itself.

Answer

According to IntelliJ's inspector (Preferences > Editor > Inspections > 'Optional' used as field or parameter type):

Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result". Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not.

This also applies to collections in case you have to serialize them. Furthermore, have a look at these links:

  • Java 8 Optional: What's the Point?

    So to recap - in an attempt to get rid of NullPointerExceptions we have a new class that:

    • Throws NullPointerExceptions
    • Can itself be null, causing a NullPointerException
    • Increases heap size
    • Makes debugging more difficult
    • Makes serializing objects, say as an XML or JSON for an external client, much more difficult
  • Why java.util.Optional is broken

    The final irony is that by attempting to discourage nulls, the authors of this class have actually encouraged its use. I'm sure there are a few who will be tempted to simply return null from their functions in order to "avoid creating an unnecessary and expensive Optional reference", rather than using the correct types and combinators.

If you care about readability, you could also use @Nullable (available in Eclipse as well as in IntelliJ):

class ConnectionBox {
    @Nullable
    Connection connection;
    // ...
}

Alternatively, you can create an optional getter:

class ConnectionBox {
    Connection connection;
    // ...
    Optional<Connection> getConnection() {
        return Optional.ofNullable(connection);
    }
}
Comments