I have a class that can contain multiple optional IDs, the class will pick the first available and return it to the caller. Something like the below.
Optional<Phone> homePhone;
Optional<Phone> mobilePhone;
Optional<Phone> emergencyPhone;
Phone getBestPhone() {
return homePhone.map(p -> p)
.orElse(mobilePhone.map(p -> p)
.orElse(emergencyPhone.map(p -> p)
.orElseThrow(() -> new IllegalArgument("No valid phone")))));
}
I'd like to use the optional methods like map and orElse but in this case it leads to way too much nesting. Two other pseudocode options might be.
Phone getBestPhone() {
homePhone.ifPresent(p -> { return p; });
mobilePhone.ifPresent(p -> { return p; });
emergencyPhone.ifPresent(p -> { return p; });
throw new IllegalArgument("...");
}
Phone getBestPhone() {
return FirstPresent(homePhone, mobilePhone, emergencyPhone);
}
Are there any better ways that the existing method I have? I'm very tempted to avoid the nesting by doing vanilla isPresent() checks.
IMO, firstPresent
approach seems more readable and extensible. We can make use of Stream#of(T...)
method to wrap those Optional
s to a stream and then find the first present.
import java.util.Optional;
import java.util.stream.Stream;
public class GetFirstPresent {
public static void main(String[] args) {
Optional<Phone> homePhone = Optional.empty();
Optional<Phone> mobilePhone = Optional.empty();
Optional<Phone> emergencyPhone = Optional.of(new Phone("e123"));
Phone phone = firstPresent(homePhone, mobilePhone, emergencyPhone);
System.out.println(phone.id);
try {
firstPresent(homePhone, mobilePhone);
} catch (IllegalArgumentException e) {
System.out.println(e);
}
}
@SafeVarargs
private static Phone firstPresent(Optional<Phone>... phones) {
return Stream.of(phones).filter(Optional::isPresent)
.findFirst().map(Optional::get).orElseThrow(() -> {
return new IllegalArgumentException("No phone present");
});
}
private static class Phone {
public Phone(String id) {
super();
this.id = id;
}
private String id;
}
}
One draw back is we need @SafeVarargs
to suppress warning, which cannot be avoided according to Is it possible to solve the “A generic array of T is created for a varargs parameter” compiler warning?