1. Introduction
In some cases, we might want to fallback to another Optional instance if another one is empty.
In this tutorial, we’ll briefly mention how we can do that – which is harder than it looks.
For an introduction to the Java Optional class, have a look at our previous article.
2. Java 8
In Java 8, there’s no direct way to achieve return a different Optional if the first one is empty.
Therefore, we can implement our own custom method:
public static <T> Optional<T> or(Optional<T> optional, Optional<T> fallback) {
return optional.isPresent() ? optional : fallback;
}
And, in practice:
@Test
public void givenOptional_whenValue_thenOptionalGeneralMethod() {
String name = "Filan Fisteku";
String missingOptional = "Name not provided";
Optional<String> optionalString = Optional.ofNullable(name);
Optional<String> fallbackOptionalString = Optional.ofNullable(missingOptional);
assertEquals(
optionalString,
Optionals.or(optionalString, fallbackOptionalString));
}
@Test
public void givenEmptyOptional_whenValue_thenOptionalGeneralMethod() {
Optional<String> optionalString = Optional.empty();
Optional<String> fallbackOptionalString = Optional.ofNullable("Name not provided");
assertEquals(
fallbackOptionalString,
Optionals.or(optionalString, fallbackOptionalString));
}
2.1. Lazy Evaluation
The above solution has one serious drawback – we need to evaluate both Optional variables before using our custom or() method.
Imagine, we have two methods returning Optionals, both querying database under the hood. It would be unacceptable, from the performance point of view, to call both of them if already the first method returns the value we need.
Let’s create a simple ItemsProvider class:
public class ItemsProvider {
public Optional<String> getNail(){
System.out.println("Returning a nail");
return Optional.of("nail");
}
public Optional<String> getHammer(){
System.out.println("Returning a hammer");
return Optional.of("hammer");
}
}
Here’s how we can chain these methods and take advantage of lazy evaluation:
@Test
public void givenTwoOptionalMethods_whenFirstNonEmpty_thenSecondNotEvaluated() {
ItemsProvider itemsProvider = new ItemsProvider();
Optional<String> item = itemsProvider.getNail()
.map(Optional::of)
.orElseGet(itemsProvider::getHammer);
assertEquals(Optional.of("nail"), item);
}
The above test case prints only “Returning a nail”. This clearly indicates that only the getNail() method has been executed.
3. Java 9
Java 9 has added an or() method that we can use to get an Optional, or another value, if that Optional isn’t present.
Let’s see this in practice with a quick example:
public static Optional<String> getName(Optional<String> name) {
return name.or(() -> getCustomMessage());
}
We’ve used an auxiliary method to help us with our example:
private static Optional<String> getCustomMessage() {
return Optional.of("Name not provided");
}
We can test it and further understand how it’s working. The following test case is a demonstration of the case when Optional has a value:
@Test
public void givenOptional_whenValue_thenOptional() {
String name = "Filan Fisteku";
Optional<String> optionalString = Optional.ofNullable(name);
assertEquals(optionalString, Optionals.getName(optionalString));
}
4. Using Guava
Another way to do this is by using or() method of the guava’s Optional class. First, we need to add guava in our project (the latest version can be found here):
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
Now, we can continue with the same example that we had earlier:
public static com.google.common.base.Optional<String>
getOptionalGuavaName(com.google.common.base.Optional<String> name) {
return name.or(getCustomMessageGuava());
}
private static com.google.common.base.Optional<String> getCustomMessageGuava() {
return com.google.common.base.Optional.of("Name not provided");
}
As we can see, it’s very similar to the one displayed above. However, it has a slight difference in the naming of the method and is exactly the same as or() method of the class Optional from JDK 9.
We can now test it, similarly as the example above:
@Test
public void givenGuavaOptional_whenInvoke_thenOptional() {
String name = "Filan Fisteku";
Optional<String> stringOptional = Optional.of(name);
assertEquals(name, Optionals.getOptionalGuavaName(stringOptional));
}
@Test
public void givenGuavaOptional_whenNull_thenDefaultText() {
assertEquals(
com.google.common.base.Optional.of("Name not provided"),
Optionals.getOptionalGuavaName(com.google.common.base.Optional.fromNullable(null)));
}
5. Conclusion
This was a quick article illustrating how to achieve Optional orElse Optional functionality.
The code for all the examples explained here, and much more can be found over on GitHub.