Funny, I happened to code something just today very similar, but a lot lighter (just two classes, Match for consuming only, and MatchMap for mapping the optional. No when/get, just a when taking two parameters : the predicate and the mapping function.
public class MatchMap<T, U> {
private final Optional<T> opt;
private final U defaultValue;
private final AtomicReference<U> result = new AtomicReference<U>();
private MatchMap(Optional<T> pOpt, U pDefault) {
super();
opt = pOpt;
defaultValue = pDefault;
}
public MatchMap<T, U> whenMatch(Predicate<T> pPred, Function<T, U> pMapFn) {
if (result.get() != null) {
return this;
}
Optional<T> lFiltered = opt.filter(pPred);
if (lFiltered.isPresent()) {
result.set(pMapFn.apply(lFiltered.get()));
}
return this;
}
public MatchMap<T, U> whenEquals(T pExact, Function<T, U> pMapFn) {
return whenMatch(t -> pExact.equals(t), pMapFn);
}
public U resolve() {
return Optional.ofNullable(result.get())
.orElse(defaultValue);
}
public static <T, U> MatchMap<T, U> of (Optional<T> pOpt, U pDefault) {
return new MatchMap<T, U>(pOpt, pDefault);
}
}
The class Match is very similar, but takes consumer instead of Function and has some logic to allow several matches to be executed (if several predicates are ok), or only allow the first match to be executed.