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 don’t know exactly know how to use them in the right way. If you use them in the wrong way, it is like you wouldn’t 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.
1 2 3 4 | 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 is Present. 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:
1 2 3 4 | 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).”
1 2 | 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:
1 2 3 4 5 | 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:
1 2 | 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.
1 2 | 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 immediately or use an orElse or an orElseThrow alternative value instead.
1 2 3 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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.
[1]: Optional Oracle JDK – https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
[3]: Optional#Filter – https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html
[4]: Optional#Map – https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
This blog post was originally featured on our Willhaben Tech Blog.