map vs flatMap
- Use flatMap when the transformation function returns an Optional: flatMap flattens it and returns Optional
instead of Optional<Optional >.
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
return !this.isPresent() ? empty() : ofNullable(mapper.apply(this.value));
}
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
Objects.requireNonNull(mapper);
if (!this.isPresent()) {
return empty();
} else {
Optional<U> r = (Optional)mapper.apply(this.value);
return (Optional)Objects.requireNonNull(r);
}
}
Filter out Optional.empty() from a stream of Optional
Can be simplified as:
stream.map(input -> returnOptional(input)).flatMap(optional -> optional.isPresent() ? Stream.of(optional.get()) : Stream.empty())
// when use Guava:
stream.map(input -> returnOptional(input)).flatMap(com.google.common.collect.Streams::stream)
Call chains of nullable API
Optional.ofNullable(new Outer())
.map(out -> out.getNested())
.map(nest -> nest.getInner())
.map(in -> in.getFoo());
orElse, orElseGet, orElseThrow
- If possible, don’t use Optional.isPresent(),
if (opt.isPresent()) {
value = opt.get();
} else {
value = default_value:
}
value = opt.orElse(default_value);
value = opt.orElseGet(() -> methodToGetDefault());
value = opt.orElseThrow(() -> new BusinessException());
When to (not) use Optional in API?
- Optionals force the user of an API to confront the fact that there may be no value returned.
- Throwing an unchecked exception or returning a null allows the user to ignore this eventuality.
- throwing a checked exception requires additional boilerplate code in the client
- (Only) Use Optional as a return type
- Return Optional.empty() in error case, or throw exception?
- Don’t use Optional as parameter for public methods or constructors
- for optional(nullable) parameters, or boolean parameter, use distinct (or overloaded) methods
- We can still use Optinonal in private implementation.
- Don’t use Optional as instance variable; Don’t use Optional within the private scope.
- Use @Nullable annotation.
- Don’t use Optional to return collection or arrays: use empty collection/arrays instead
public static Optional<Integer> parseInt(String string) {
try {
return Optional.of(Integer.parseInt(string));
} catch (NumberFormatException e) {
logger.error("Unable to parse {} as int", string, e);
return Optional.empty();
}
}
Other Tips about Optional
- Never assign null to an optional.
- Make sure an optional has a value before calling get().
- or use ifPresent, orElse, orElseGet
- Optional is not Serializable
- Be careful of the difference between Optional.of() and Optional.ofNullable()
- Use java.util.OptionalInt/Long/Double, never return an optional of a boxed primitive type.
Methods of Optional
- ifPresent, filter, map, flatMap
New methods after Java 8
- Use stream() method on Optional instance to treat Optional instance as a Stream
- Use .flatMap(Optional::stream) instead of .filter(Optional::isPresent).map(Optional::get)
- .or(Supplier<? extends Optional<? extends T>> supplier)
- .ifPresentOrElse(action, emptyAction)
- Optional.isEmpty()
When work with legacy code
- com.google.common.base.Optional.toJavaUtil/fromJavaUtil
Example of Using Optinonal
if (cacheExpirationInSeconds != null) {
return Optional.of(Instant.now().plusSeconds(cacheExpirationInSeconds));
}
return Optional.empty();
Can be simplified as: