Java 8 introduced the Optional
class to make handling of nulls less error-prone. For example, the following program to pick the lucky name has a null check as:
public static final List<String> NAMES = Arrays.asList("Rita", "Gita", "Nita", "Ritesh", "Nitesh", "Ganesh", "Yogen", "Prateema"); public String pickLuckyNameOldWay(final List<String> names, final String startingLetter) { String luckyName = null; for (String name : names) { if (name.startsWith(startingLetter)) { luckyName = name; break; } } return luckyName != null ? luckyName : "No lucky name found"; }
This null check can be replaced with the Optional
class method isPresent()
as shown below:
public String pickLuckyNameWIsPresent(final List<String> names, final String startingLetter) { final Optional<String> luckyName = names.stream().filter(name -> name.startsWith(startingLetter)).findFirst(); return luckyName.isPresent() ? luckyName.get() : "No lucky name found"; }
However, notice the writing is no easier than:
return luckyName != null ? luckyName : "No lucky name found";
The Optional
class, however, supports other techniques that are superior to checking nulls. The above code can be re-written as below with orElse()
method as below:
public String pickLuckyNameWOrElse(final List<String> names, final String startingLetter) { final Optional<String> luckyName = names.stream().filter(name -> name.startsWith(startingLetter)).findFirst(); return luckyName.orElse("No lucky name found"); }
The method orElse()
is invoked with the condition "If X is null, populate X. Return X.", so that the default value can be set if the optional value is not present.
There is another method called the ifPresent(Function)
. You can use this method to invoke an action and skip the null case completely. For example, the program below prints a message in the case, if the condition is met as:
public static void pickLuckyNameOldWay(final List<String> names, final String startingLetter) { String luckyName = null; for (String name : names) { if (name.startsWith(startingLetter)) { luckyName = name; break; } } if (luckyName != null) { postMessage(luckyName); } } public static void postMessage(final String winnerName) { System.out.println(String.format("Congratulations, %s!", winnerName)); }
This can be re-written with ifPresent()
, as shown below. in a more intuitive manner, as:
public static void pickLuckyNameNewWay(final List<String> names, final String startingLetter) { final Optional<String> luckyName = names.stream().filter(name -> name.startsWith(startingLetter)).findFirst(); luckyName.ifPresent(OptionalIfPresent::postMessage); }
If we want to throw an exception in case if no name is found, then it would be something like this:
public String pickLuckyNameOldWay(final List<String> names, final String startingLetter) { String luckyName = null; // ... same code here if (luckyName == null) { throw new NotFoundException("There is no name starting with letter."); } return luckyName; }
It can be meaningfully replaced with orElseThrow
as:
public String pickLuckyNameWOrElse(final List<String> names, final String startingLetter) { final Optional<String> luckyName = names.stream().filter(name -> name.startsWith(startingLetter)).findFirst(); return luckyName.orElseThrow(() -> new NotFoundException("There is no name starting with letter.")); }
There are other many more methods in the Optional
class to handle null
in more proper way. You can go through the Optional in Java 8 cheat sheet.
As always, if you want to look into the source code for the example presented above, they are available on GitHub.