Java 8 Optional
Introduction
As the Optional documentation states, it's a container object which may or may not contain a non-null value. Google Guava library users may be already familiar with the Optional class since it was already included in the library.
The Optional goal is to correctly represent an eventually null value at an arbitrary application code location.
The usage of the Optional class will also lead to a lesser number of null pointer exceptions at application runtime. This assumption has lead to many discussions around the subject, since the Optional class will also throw an exception if we try to access its value while the value is null. The whole point of the Optional class is that developers will know that when they face an Optional - and consequently are forced to unwrap its value - they must account for the null value possibility (and of course, as it may already be clear, Optional also gives API developers a proper way of representing the null value possibility).
Let's see a comparison:
User findUser(Long userId);
If a developer is including some 3rd party API which contains the aforementioned findUser method, he may not immediately know what happens if he provides a userId that does not correspond to any user: will the method return a null reference? Will it throw an exception? Let's see the Optional variant of the same method:
Optional<User> findUser(Long userId);
Just by looking at the method signature it now becomes clear that the method may return an Optional containing a null value. Since we now have to explicitly unwrap the Optional contained instance, it's mandatory (and hard to forget or avoid) to account for the possibility of the wrapped value being a null reference.
The Optional
Let's see the Optional in practice:
String value = "Hello"; Optional<String> optionalString = Optional.of(value); System.out.println(optionalString.isPresent()); // Will print true System.out.println(optionalString.get()); // Will print "Hello" // ----------------------------------------- String value = null; Optional<String> optionalString = Optional.of(value); // Will throw NullPointerException // ----------------------------------------- String value = null; Optional<String> optionalString = Optional.ofNullable(value); System.out.println(optionalString.isPresent()); // Will print false System.out.println(optionalString.get()); // Will throw NoSuchElementException // ----------------------------------------- String value = null; Optional<String> optionalString = Optional.ofNullable(value); System.out.println(optionalString.isPresent()); // Will print false System.out.println(optionalString.orElse("other")); // Will print "other"
Optionals may also be used with Consumers and Suppliers:
(More info about Consumers and Suppliers in the following article: Java 8 Consumer and Supplier).
String value = "Hello"; Optional<String> optionalString = Optional.of(value); System.out.println(optionalString.isPresent()); // Will print true optionalString.ifPresent((s) -> System.out.println(s.length())); // Will print 5 // ----------------------------------------- void run(){ String value = null; Optional<String> optionalString = Optional.ofNullable(value); System.out.println(optionalString.isPresent()); // Will print false System.out.println(optionalString.orElseGet(Test::getString)); // Will print "Hello" } static String getString() { return "Hello"; }
Optionals may also be used with Predicates and Functions:
(More info about Predicates and Functions in the following article: Java 8 Predicates and Functions).
String value = "Hello"; Optional<String> optionalString = Optional.ofNullable(value); System.out.println(optionalString.isPresent()); // Will print true Optional<String> otherOptional = optionalString.filter((s) -> s.length() > 4); System.out.println(otherOptional.isPresent()); // Will print true System.out.println(otherOptional.get()); // Will print "Hello" Optional<String> anotherOptional = optionalString.filter((s) -> s.length() > 5); System.out.println(anotherOptional.isPresent()); // Will print false // ----------------------------------------- String value = "Hello"; Optional<String> optionalString = Optional.of(value); System.out.println(optionalString.isPresent()); // Will print true Optional<Integer> optionalInteger = optionalString.map((s) -> s.length()); System.out.println(optionalInteger.get()); // Will print 5 Optional<Integer> otherOptionalInteger = optionalString.map((s) -> s.length() > 5 ? s.length() : null); System.out.println(otherOptionalInteger.isPresent()); // Will print false