How to Use the Java Optional Properly
0 CommentsLast Updated on October 20, 2024 by jt
One of the exceptions that every Java Programmer must have faced is NullPointerException. They are hard to debug and cause unexpected termination of your application. To better handle NullPointerException
, Java 8 has introduced the Optional class.
In this post, I’ll explain how to use Optional
in Java applications.
Optional Overview
The main benefit of the Optional
class is that it prevents unwanted NullPointerExceptions
.
Consider this code.
NPEExample.java
package guru.springframework.optionaldemos; public class NPEExample { static String convert(String[] strArr, int index){ if(strArr[index]!=null) return strArr[index].toUpperCase(); else return "Please provide valid input"; } public static void main(String[] args) { String[] strArr= new String[5]; String convertedValue= convert(strArr,3); System.out.println(convertedValue); } }
When you run the preceding code, you get NullPointerException
, like this.
To prevent this, we can do explicit null checks, like this.
NPEExample.java
package guru.springframework.optionaldemos; public class NPEExample { static String convert(String[] strArr, int index){ if(strArr[index]!=null) return strArr[index].toUpperCase(); else return "Please provide valid input"; } public static void main(String[] args) { String[] strArr= new String[5]; String convertedValue= convert(strArr,3); System.out.println(convertedValue); } }
With Optional
, the code will now look like this.
String res; String[] strArr= new String[6]; Optional<String> checkNull = Optional.ofNullable(strArr[5]); if (checkNull.isPresent()) { res = convert(strArr, 5); System.out.println(res); } else System.out.println("Value is not present");
In the preceding code, the ofNullable()
method returns an Optional
describing the given value, if non-null. Otherwise, this method returns an empty Optional
. In the preceding code the method returns an empty Optional
.
The isPresent()
method returns true
if a value is present. Otherwise, it returns false
. In the preceding code, the isPresent()
method will return false
, and the program will output Value is not present
.
Creating Optional Objects
The Optional
class comes with a number of static methods to create Optional
objects. The methods are:
empty()
of()
ofNullable()
The empty() Method
private static void emptyOptioal() { /*Empty Optional*/ Optional<String> empty = Optional.empty(); if(empty.isEmpty()){ System.out.println("I am an empty optional"); }
The preceding code returns an empty Optional
. No value is present for this Optional
.
Note: Though, it may be tempting to do check for presence, avoid testing if an object is empty by comparing with {==} against instances returned by Option.empty()
. There is no guarantee that it is a singleton. Instead, use isPresent()
.
The of() Method
The next method is of()
. This method returns an Optional
with the specified present non-null value.
private static void optionalOf() { String name = "Optional"; Optional<String> opt = Optional.of(name); System.out.println(opt); }
The preceding of()
method expects a non-null argument. Otherwise, it will throw a NullPointerException
. So take precaustion of caaling this method, if you are not sure whether the parameter is null or not null.
The best practice is to use the ofNullable()
method.
The ofNullable() Method of the Optional Class
The ofNullable ()
method returns an Optional
describing the specified value, if non-null, otherwise returns an empty Optional
.
You can refactor your code like this:
// Possible null value Optional<String> optional = Optional.ofNullable(getName()); private static String getName(){ String name = "Im an Optional"; return (name.length() > 5) ? name : null; }
In the preceding code, if we pass in a null reference, it doesn’t throw an exception but rather returns an empty Optional
object:
Below is the code, you can refer to.
OptionalCreation.java
package guru.springframework.optionaldemos; import java.util.Optional; public class OptionalCreation { public static void main(String[] args) { emptyOptioal(); optionalOf(); // Possible null value Optional<String> optional = Optional.ofNullable(getName()); System.out.println(optional); } private static String getName(){ String name = "Im an Optional"; return (name.length() > 5) ? name : null; } private static void optionalOf() { String name = "Optional"; Optional<String> opt = Optional.of(name); System.out.println(opt); } private static void emptyOptioal() { /*Empty Optional*/ Optional<String> empty = Optional.empty(); if(empty.isEmpty()){ System.out.println("I am an empty optional"); } } }
Checking for Values in an Optional
The Optional
class has two methods called isEmpty()
and isPresent()
. Both the methods return a boolean
value which indicates whether or not a value is present in the Optional
.
The isEmpty()
method checks If a value is not present, and accordingly will returns true
, otherwise false
.
On the other hand, the isPrsent()
method returns true If a value is present,, otherwise false.
The code to use the methods is this.
Optional op1 = Optional.empty(); System.out.println(op1.isEmpty()); System.out.println(op1.isPresent()); Optional op2 = Optional.of("Optional"); System.out.println(op2.isEmpty()); System.out.println(op2.isPresent());
The output of the preceding code is this.
true false false true
OrElse() and OrElseGet() of the Optional Class
Optional
comes with the
orElse()
method that will always call the given function whether you want it or not. It is also regardless of Optional.isPresent()
value.
The following code shows an example of orElse()
method.
Optional<Integer> op = Optional.empty(); // print value System.out.println("Optional: " + op); if(op.isEmpty()) // orElse value System.out.println("Value by orElse " + op.orElse(100));
Note: On the other hand, orElseGet()
will only call the given function when the Optional.isPresent() == false
.
Retrieving Values from Optional
The Optional
class provides a get()
method that returns the value if present in the Optional
. Otherwise, this method throws NoSuchElementException
.
The following code shows using the get()
method.
package guru.springframework.optionaldemos; import java.util.Optional; public class OptionalGet { public static void main(String[] args) { Optional op1 = Optional.of("Hello World"); System.out.println(op1.orElse("Default Value")); Optional opt2=Optional.empty(); System.out.println(opt2.orElse("Default Value")); } }
The output of the preceding code is this.
Hello World Exception in thread "main" java.util.NoSuchElementException: No value present at java.base/java.util.Optional.get(Optional.java:143) at guru.springframework.optionaldemos.OptionalGet.main(OptionalGet.java:10)
To avoid the exception, you can use the orElse()
method to return a default value, like this.
Optional op1 = Optional.of("Hello World"); System.out.println(op1.orElse("Default Value")); Optional opt2=Optional.empty(); System.out.println(opt2.orElse("Default Value"));
The output of the preceding code is this.
Hello World Default Value
The Optional
class provides a orElseThrow()
method that you can use to throw a custom exception when a value is not present in the Optional
.
An example to use the orElseThrow()
method is this.
OptionOrElseThrow.java
package guru.springframework.optionaldemos; import java.util.Optional; public class OptionOrElseThrow { public static void main(String[] args) throws Throwable { String email= null; Optional emailOpt=Optional.ofNullable(email); System.out.println(emailOpt.orElseThrow(()->new IllegalArgumentException("Email cannot be null"))); } }
The output on running the preceding code is this.
Exception in thread "main" java.lang.IllegalArgumentException: Email cannot be null
Performing Operations on Optional
The filter() Method
The Optional
class contains a filter()
method that filters a value, if present, against a given predicate. This method returns an Optional
describing the value.
If there is no value present in the Optional
, then this method returns an empty Optional
object.
An example of using the filter()
method is this.
private static void filterDemo() { Optional opt1=Optional.of("Hello! Optional Example"); Predicate<String> predicate1 = s -> s.contains("Example"); Optional<String> result1 = opt1.filter(predicate1); System.out.println(result1.isPresent()); Predicate<String> predicate2 = s -> s.startsWith("Hello"); Optional<String> result2 = opt1.filter(predicate2); System.out.println(result2.isPresent()); }
The output of the preceding code is this.
true true
The map() Method
The map()
method of Optional
returns an Optional
describing the result of applying the given mapping function to the value in the Optional
. If no value is present this method returns an empty Optional
.
The following code shows the use of the map()
method.
private static void mapDemo() { Optional<String> opt1=Optional.of("Hello! Optional Example"); System.out.println(opt1.map(String::toUpperCase).get()); }
The output on calling the preceding method is this.
HELLO! OPTIONAL EXAMPLE
Summary
The Optional
class is an attempt to reduce the number of null pointer exceptions in Java systems. However, I have seen developers using Optional
incorrectly.
One common mistake is assigning null to an optional variable, like this.
public Optional<Product> getProduct(int id) { // perform a search for product Optional<Product> product = null; // in case no product return product; }
The correct approach is to replace the line, which initializes the Optional
with an empty Optional like this.
Optional<Product> product = Optional.empty();
Another typical mistake developers make is directly calling the get()
method. If the Optional
is empty, the call to get will throw NoSuchElementException
. Instead always do a check with the isPresent()
method before calling get()
.
The source code of this post is present on Github.