September 27, 2016

Optionals in Java 8 and How to Use Them

Since the release of Java 8, NullPointerExceptions shouldn't be common anymore. Before Java 8, your code was probably full of "if statements" to check if a variable was null. Still, it was impossible to catch every NullPointerException out there. With Java 8, Oracle attempted to solve this issue. They didn’t invent the holy grail, but they did make our lives as developers much easier by helping prevent code smells and those nasty Exceptions. Now, if you start a new project, you should definitely use Java 8 to avoid NullPointerExceptions.

So what exactly did Oracle do to help us in our misery? They introduced Optionals. [1]

You may have heard of Optionals already a few times, but you maybe dont know exactly know how to use them in the right way. If you use them in the wrong way, it is like you wouldnt use Optionals at all. So let's take a look how Optionals could be used.


Usage Scenarios

You may have the urge to use an Optional like we do in the following example. However, this wouldn't be much different than just using a null check, and it’s not any easier to read.
  Optional<Integer> myFirstOptional = myService.getSomeOptionalInteger();   
  if(myFirstOptional.get() == 2) {   
   System.out.println("Is this the correct use of Optionals?")   
  }   

A better way to utilize Optionals is to check first if the Optional isPresent. If you don't do that, you can also run into a NullPointerException and you don‘t win anything at all. The following example, then, is an improvement over the first:
  Optional<Integer> myFirstOptional = myService.getSomeOptionalInteger();   
  if(myFirstOptional.isPresent()) {   
   int someInt = myFirstOptional.get();   
  }   

If you are going to use Optionals like this, you can still go the old route by just checking if the value returned by the service is null or not. Because Optionals are designed to be used in a different way.


IfPresent

The ifPresent Method requires a Consumer Function [2].
"Represents an operation that accepts a single input argument and returns no result. Unlike most other functional interfaces, Consumer is expected to operate via side-effects. This is a functional interface whose functional method is accept(Object)."
  Optional<Integer> myFirstOptional = myService.getSomeOptionalInteger();   
  myFirstOptional.ifPresent(myInt -> System.out.println(myInt));   

OrElse 

The following would be one approach to printing the Optional's value:
  Optional<Integer> myFirstOptional = myService.getSomeOptionalInteger();   
  myFirstOptional.ifPresent(myInt -> System.out.println(myInt));   
  if(!myFirstOptional.isPresent()) {   
   System.out.println(3);   
  }   

However, this approach is overly complicated. If you want to print the Integer of the Optional you can instead use the shortcut orElse. This way, you have the option to print the Integer directly (or print an alternative value if the value is null). It also makes the code more readable and easier on the eyes:
 Optional<Integer> myFirstOptional = myService.getSomeOptionalInteger();   
 System.out.println(myFirstOptional.orElse(5));   

When using orElse, you could also use an exception instead of an alternative value.
  Optional<Integer> myFirstOptional = myService.getSomeOptionalInteger();   
  myFirstOptional.orElseThrow(RuntimeException::new);   


Filter

The Filter method [3] takes a predicate as an argument, and returns an Optional. This method is great for performing some checks on the Optional first, and, if it matches the filter predicate you can use the value immediatly or use an orElse or an orElseThrow alternative value instead.
  int someInt = myFirstOptional   
      .filter(myInt -> myInt == 3)   
      .orElse(5);   

Map

The map method [4] can also be used to work with an Optional. The map method takes a function as an argument and returns an Optional. If you do not want to receive an Optional from the map method, you have to use orElse with it, as shown below:
 private class SomeObject {   
    private int id;   
    private String description;   
    public SomeObject(int id, String description) {   
     this.id = id;   
     this.description = description;   
    }   
    public int getId() {   
     return id;   
    }   
    public String getDescription() {   
     return description;   
    }   
   }   
  Optional<SomeObject> myFirstOptional = Optional.of(new SomeObject(1, "Test"));   
  final String someString = myFirstOptional  
                  .map(myObject -> myObject.getDescription())  
                  .orElse("Alternative value");   


Summary

Introducing Optionals to Java 8 was a great move by Oracle. If you are going to use Optionals in your code and try to refactor old code wherever possible, you should be able to get rid of most of your NullPointerExceptions and code smell. Optionals help developers, allowing us to not have to think about if we forgot about catching a NullPointerException since the IDE will always notify you if an Optional is used incorrectly. If you use a Code Quality Tool like SonarQube, you will notice this too.

All in all, Optionals can really help improve your code quality, but only if you use them right. So, take some time to get used to this new concept.

3 comments:

  1. Thanks for providing this informative information. it is very useful you may also refer-http://www.s4techno.com/blog/category/java/

    ReplyDelete
  2. Hi, I am captivating a Computer Science class and I am virtually done with my mission which is creating a Flamingo Video.

    ReplyDelete
  3. thank you for downloading this launch of the java™ platform, general edition improvement kit (jdk™). the jdk is a improvement environment for constructing programs in dissertation company UK applets, and components the use of the java programming language.

    ReplyDelete