Favor Optional Over Null

 class​ Communicator {
 
  Connection connectionToEarth;
 
 void​ establishConnection() {
 // used to set connectionToEarth, but may be unreliable
  }
 
  Connection getConnectionToEarth() {
»return​ connectionToEarth;
  }
 }

References that don’t point to an object point to the null reference instead. If you try to call a method on a null reference, you cause a NullPointerException. This is probably the most well-known exception in Java.

Using null references is fine for internal state where you have full control over how the reference is accessed. But exposing it makes the program fragile because every caller needs to check for null, which is something that people easily forget. This is what we’ve discussed in Avoid Returning Null. But since Java 8 and lambda expressions, we have an alternative to the null object solution.

In the code above, the Connection might not always be available and connectionToEarth can be null. This can be a problem if the calling code doesn’t check for null. Consider the following:

»communicator.getConnectionToEarth()
  .send(​"Houston, we got a problem!"​);

This code can trigger the dreaded NullPointerException if there’s no connection available.

But it’s easy to fix. We just need to add an if statement to check whether the connection we get from calling the getter isn’t null.

Still, writing the fix isn’t the hard part. That’s detecting the issue before that code goes into production. Because you use references everywhere in Java, there’s simply too much potential for null references to creep in. Every Java program runs into NullPointerException at some point during development.

What’s more, you can’t really combine the fix with the if statement with lambda expressions in an elegant way. You’d have to separate the expression into several lines instead. But there’s a better solution.

How can we make it explicit that a connectionToEarth might be absent?

 class​ Communicator {
 
  Connection connectionToEarth;
 
 void​ establishConnection() {
 // used to set connectionToEarth, but may be unreliable
  }
 
  Optional<Connection> getConnectionToEarth() {
»return​ Optional.ofNullable(connectionToEarth);
  }
 }

With the Optional. An Optional is a placeholder for an object that may or may not be present. You create it by calling Optional.ofNullable() with a reference that may point to an object or to null. Here, a connectionToEarth is either there or it isn’t.

The big difference is that you can now spot the potential unavailability in the method signature. Consider the following usage:

 Connection connection = communicator.getConnectionToEarth()
» .orElse(​null​);
 connection.send(​"Houston, we got a problem!"​);

This reproduces the same behavior as the usage before, including the NullPointerException. But it shows that either we get a Connection object orElse we get null.

Instead of hiding a null value in the Communicator, the Optional reveals it in the caller’s code where the access would happen. That way, the Optional forces the caller to think about how to handle an absent value. If you do this as above (orElse(null)), you’ll still cause exceptions. So let’s fix this here and now:

 communicationSystem.getConnectionToEarth()
» .ifPresent(connection ->
  connection.send(​"Houston, we got a problem!"​)
  );

Without an Optional at hand, we would fix this with an if statement. But the Optional provides a handy method: ifPresent(). This method executes a Consumer you pass in, but only if the value within the Optional isn’t null. Here, we simply pass in a Consumer that sends messages. NullPointerException prevented!

A null object for Connection could’ve solved this, too. But here we resort to a generic null object: Optional.empty(). This saves us development effort, but it’s at the expense of having to handle the null object explicitly every time. With lambdas, the Optional class is usually the way to go.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.48.161