Correct Usage of Java 8 Optional


Optional is a new type of Java 8. I saw it before with scala and was quite impressed. You know Tony Hoare’s “billion-dollar mistake”: the null reference. How many NullPointerExceptions have you yet? The type Optional wants to fix that. With Optional you won’t get any NullPointerExceptions anymore. But it is important to use Optional the right way. So don’t disappoint Hoare and take the chance to fix the billion-dollar mistake.

Return values

If you have a method with a result which sometimes may be empty, don’t return null. Even if you add a comment to your method. They will not always read it.

/**
* @return an object or else null.
*/
public Object getSomething() {
  if (haveObject) {
    return object;
  } else {
    return null;
  }
}

You should tell your user and the compiler that they can not be sure to get an object or not. Use the Optional:

/**
* @return Optional of Object
*/
public Optional<Object> getSomething() {
  if (haveObject) {
    return Optional.of(new Object());
  } else {
    return Optional.empty();
  }
}

Only do if not null

Consuming an optional value you probably want to do something only if a value is present. You could do it by using the method isPresent():

public void doOnlyIfPresentComplicated() {
  Optional<Object> something = logic.getSomething();
  if (something.isPresent()) {
    System.out.println(something.get());
  }
}

But this is not much of a progress compared to writing if (something != null). This is where the lambda expressions of optional come into play. Using ifPresent() you can write this much better:

 public void doOnlyIfPresent() {
   logic.getSomething().ifPresent(System.out::println);
 }

Avoid nested null checks

Sometimes you have several optional values in a row. Only if all optionals return a value, you want to return an http 200. Http 404 should be returned if somewhere in the chain there is no value. Again there is a complicated way:

public Response avoidNullChecksComplicated() {
  Optional<Object> something = logic.getSomething();
  if (something.isPresent()) {
    Optional<Object> otherOptional = logic.otherOptional(something.get());
    if (otherOptional.isPresent()) {
      Optional<Object> lastOptional = logic.lastOptional(otherOptional.get());
      if (lastOptional.isPresent()) {
        return Response.ok(lastOptional.get()).build();
      }
    }
  }
  return Response.status(Status.NOT_FOUND).build();
}

Or you avoid the nested if statements and simply use flatMap and method references:

 public Response avoidNullChecks() {
   return logic.getSomething() //
     .flatMap(this::getOtherOptional) //
     .flatMap(this::getLastOptional) //
     .map(this::getOKResponse) //
     .orElse(get404Response());
 }

 private Optional<Object> getOtherOptional(Object o) {
   return logic.otherOptional(o);
 }

 private Optional<Object> getLastOptional(Object o) {
   return logic.lastOptional(o);
 }

 private Response getOKResponse(Object o) {
   return Response.ok(o).build();
 }

 private Response get404Response() {
   return Response.status(Status.NOT_FOUND).build();
 }

I think it is much better than the nested if statements. If you use all Optionals the right way, your code stays readable and you can fix some of the “billion-dollar mistake”.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s