Created
October 15, 2019 01:07
-
-
Save edreyer/4a0524a986227dceb32e88fc4e5679f9 to your computer and use it in GitHub Desktop.
Adds some useful operations to Java 8's Optional
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Objects; | |
import java.util.Optional; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import java.util.function.Predicate; | |
import java.util.function.Supplier; | |
/** | |
* Wraps Java's Optional to provide some additional capabilities | |
* | |
* Example | |
* <pre> | |
* int x = 1; | |
* int len = Option. | |
* when(x == 0, () -> "foo"). | |
* when(x == 1, "bar"). | |
* peek(it -> println("value is " + it)). | |
* filter(it -> it.length() % 2 == 0). | |
* onEmpty(() -> println("Do this if empty")). | |
* orElseOp(() -> CGOptional.of("baz")). | |
* map(String::length). | |
* orElseThrow(() -> new IllegalStateException()); | |
* // OR orElse(100) | |
* // OR toOptional() | |
* // OR ifPresent(a -> ...) | |
* // etc | |
* </pre> | |
*/ | |
public final class Option<T> { | |
private Optional<T> op; | |
private Option(Optional<T> op) { | |
this.op = op; | |
} | |
/** */ | |
public static <T> Option<T> of(T value) { | |
return of(Optional.of(value)); | |
} | |
/** */ | |
public static <T> Option<T> of(Optional<T> op) { | |
return new Option(op); | |
} | |
/** */ | |
public static <T> Option<T> empty() { | |
return of(Optional.empty()); | |
} | |
/** */ | |
public static <T> Option<T> ofNullable(T value) { | |
return of(Optional.ofNullable(value)); | |
} | |
/** */ | |
public static <T> Option<T> when(boolean condition, Supplier<? extends T> supplier) { | |
Objects.requireNonNull(supplier, "supplier is null"); | |
return condition ? of(supplier.get()) : empty(); | |
} | |
/** */ | |
public static <T> Option<T> when(boolean condition, T value) { | |
return condition ? of(value) : empty(); | |
} | |
/** | |
* null-safe toString. Returns empty String if null | |
*/ | |
public static <A> String toString(A obj) { | |
return ofNullable(obj).toString(); | |
} | |
/** */ | |
public Option<T> orElseOp(T other) { | |
return op.isPresent() ? this : ofNullable(other); | |
} | |
/** */ | |
public Option<T> orElseOp(Option<T> other) { | |
return op.isPresent() ? this : other; | |
} | |
/** */ | |
public Option<T> orElseOp(Supplier<Option<T>> supplier) { | |
return op.isPresent() ? this : supplier.get(); | |
} | |
/** */ | |
public Optional<T> toOptional() { | |
return op; | |
} | |
/** nullSafe toString() */ | |
@Override | |
public String toString() { | |
return op.map(Object::toString).orElse(""); | |
} | |
/** */ | |
public boolean isPresent() { | |
return op.isPresent(); | |
} | |
/** */ | |
public boolean isEmpty() { | |
return !op.isPresent(); | |
} | |
/** */ | |
public void ifPresent(Consumer<? super T> consumer) { | |
op.ifPresent(consumer); | |
} | |
/** */ | |
public Option<T> onEmpty(Runnable action) { | |
Objects.requireNonNull(action, "action is null"); | |
if (!isPresent()) { | |
action.run(); | |
} | |
return this; | |
} | |
/** */ | |
public Option<T> peek(Consumer<? super T> action) { | |
Objects.requireNonNull(action, "action is null"); | |
if (isPresent()) { | |
action.accept(op.get()); | |
} | |
return this; | |
} | |
/** */ | |
public Option<T> filter(Predicate<? super T> predicate) { | |
return of(op.filter(predicate)); | |
} | |
/** */ | |
public <U> Option<U> map(Function<? super T, ? extends U> mapper) { | |
return of(op.map(mapper)); | |
} | |
/** */ | |
public <U> Option<U> flatMap(Function<? super T, Optional<U>> mapper) { | |
return of(op.flatMap(mapper)); | |
} | |
static <T> Optional<List<T>> sequence(Iterable<? extends Optional<? extends T>> values) { | |
Objects.requireNonNull(values, "values is null"); | |
List<T> list = new ArrayList<>(); | |
for (Optional<? extends T> value : values) { | |
if (!value.isPresent()) { | |
return Optional.empty(); | |
} | |
list.add(value.get()); | |
} | |
return Optional.of(list); | |
} | |
/** */ | |
public T get() { | |
return op.get(); | |
} | |
/** */ | |
public T orElse(T other) { | |
return op.orElse(other); | |
} | |
/** */ | |
public T orElseGet(Supplier<? extends T> other) { | |
return op.orElseGet(other); | |
} | |
/** */ | |
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { | |
return op.orElseThrow(exceptionSupplier); | |
} | |
@Override public boolean equals(Object o) { | |
if (this == o) { | |
return true; | |
} | |
if (o == null || getClass() != o.getClass()) { | |
return false; | |
} | |
Option<?> that = (Option<?>) o; | |
return Objects.equals(op, that.op); | |
} | |
@Override public int hashCode() { | |
return op != null ? op.hashCode() : 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment