/* __ __ __ __ __ ___ * \ \ / / \ \ / / __/ * \ \/ / /\ \ \/ / / * \____/__/ \__\____/__/.ɪᴏ * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ */ package io.vavr.control; import io.vavr.PartialFunction; import io.vavr.Value; import io.vavr.collection.Iterator; import io.vavr.collection.Seq; import io.vavr.collection.Vector; import java.io.Serializable; import java.util.NoSuchElementException; 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; /** * Replacement for {@link java.util.Optional}. * <p> * Option is a <a href="http://stackoverflow.com/questions/13454347/monads-with-java-8">monadic</a> container type which * represents an optional value. Instances of Option are either an instance of {@link Some} or the * singleton {@link None}. * <p> * Most of the API is taken from {@link java.util.Optional}. A similar type can be found in <a * href="http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-Maybe.html">Haskell</a> and <a * href="http://www.scala-lang.org/api/current/#scala.Option">Scala</a>. * * @param <T> The type of the optional value. * @author Daniel Dietrich */ public interface Option<T> extends Value<T>, Serializable { long serialVersionUID = 1L; /** * Creates a new {@code Option} of a given value. * * @param value A value * @param <T> type of the value * @return {@code Some(value)} if value is not {@code null}, {@code None} otherwise */ static <T> Option<T> of(T value) { return (value == null) ? none() : some(value); } /** * Reduces many {@code Option}s into a single {@code Option} by transforming an * {@code Iterable<Option<? extends T>>} into a {@code Option<Seq<T>>}. If any of * the Options are {@link Option.None}, then this returns {@link Option.None}. * * @param values An {@code Iterable} of {@code Option}s * @param <T> type of the Options * @return An {@code Option} of a {@link Seq} of results * @throws NullPointerException if {@code values} is null */ static <T> Option<Seq<T>> sequence(Iterable<? extends Option<? extends T>> values) { Objects.requireNonNull(values, "values is null"); Vector<T> vector = Vector.empty(); for (Option<? extends T> value : values) { if (value.isEmpty()) { return Option.none(); } vector = vector.append(value.get()); } return Option.some(vector); } /** * Creates a new {@code Some} of a given value. * <p> * The only difference to {@link Option#of(Object)} is, when called with argument {@code null}. * <pre> * <code> * Option.of(null); // = None * Option.some(null); // = Some(null) * </code> * </pre> * * @param value A value * @param <T> type of the value * @return {@code Some(value)} */ static <T> Option<T> some(T value) { return new Some<>(value); } /** * Returns the single instance of {@code None} * * @param <T> component type * @return the single instance of {@code None} */ static <T> Option<T> none() { @SuppressWarnings("unchecked") final None<T> none = (None<T>) None.INSTANCE; return none; } /** * Narrows a widened {@code Option<? extends T>} to {@code Option<T>} * by performing a type-safe cast. This is eligible because immutable/read-only * collections are covariant. * * @param option A {@code Option}. * @param <T> Component type of the {@code Option}. * @return the given {@code option} instance as narrowed type {@code Option<T>}. */ @SuppressWarnings("unchecked") static <T> Option<T> narrow(Option<? extends T> option) { return (Option<T>) option; } /** * Creates {@code Some} of suppliers value if condition is true, or {@code None} in other case * * @param <T> type of the optional value * @param condition A boolean value * @param supplier An optional value supplier, may supply {@code null} * @return return {@code Some} of supplier's value if condition is true, or {@code None} in other case * @throws NullPointerException if the given {@code supplier} is null */ static <T> Option<T> when(boolean condition, Supplier<? extends T> supplier) { Objects.requireNonNull(supplier, "supplier is null"); return condition ? some(supplier.get()) : none(); } /** * Creates {@code Some} of value if condition is true, or {@code None} in other case * * @param <T> type of the optional value * @param condition A boolean value * @param value An optional value, may be {@code null} * @return return {@code Some} of value if condition is true, or {@code None} in other case */ static <T> Option<T> when(boolean condition, T value) { return condition ? some(value) : none(); } /** * Wraps a Java Optional to a new Option * * @param optional a given optional to wrap in {@code Option} * @param <T> type of the value * @return {@code Some(optional.get())} if value is Java {@code Optional} is present, {@code None} otherwise */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") static <T> Option<T> ofOptional(Optional<? extends T> optional) { Objects.requireNonNull(optional, "optional is null"); return optional.<Option<T>>map(Option::of).orElseGet(Option::none); } /** * Collects value that is in the domain of the given {@code partialFunction} by mapping the value to type {@code R}. * * <pre>{@code * partialFunction.isDefinedAt(value) * }</pre> * * If the element makes it through that filter, the mapped instance is wrapped in {@code Option} * * <pre>{@code * R newValue = partialFunction.apply(value) * }</pre> * * * @param partialFunction A function that is not necessarily defined on value of this option. * @param <R> The new value type * @return A new {@code Option} instance containing value of type {@code R} * @throws NullPointerException if {@code partialFunction} is null */ default <R> Option<R> collect(PartialFunction<? super T, ? extends R> partialFunction) { Objects.requireNonNull(partialFunction, "partialFunction is null"); return filter(partialFunction::isDefinedAt).map(partialFunction::apply); } /** * Returns true, if this is {@code None}, otherwise false, if this is {@code Some}. * * @return true, if this {@code Option} is empty, false otherwise */ @Override boolean isEmpty(); /** * Runs a Java Runnable passed as parameter if this {@code Option} is empty. * * @param action a given Runnable to be run * @return this {@code Option} */ default Option<T> onEmpty(Runnable action) { Objects.requireNonNull(action, "action is null"); if (isEmpty()) { action.run(); } return this; } /** * An {@code Option}'s value is computed synchronously. * * @return false */ @Override default boolean isAsync() { return false; } /** * Returns true, if this is {@code Some}, otherwise false, if this is {@code None}. * <p> * Please note that it is possible to create {@code new Some(null)}, which is defined. * * @return true, if this {@code Option} has a defined value, false otherwise */ default boolean isDefined() { return !isEmpty(); } /** * An {@code Option}'s value is computed eagerly. * * @return false */ @Override default boolean isLazy() { return false; } /** * An {@code Option} is single-valued. * * @return {@code true} */ @Override default boolean isSingleValued() { return true; } /** * Gets the value if this is a {@code Some} or throws if this is a {@code None}. * * @return the value * @throws NoSuchElementException if this is a {@code None}. */ @Override T get(); /** * Returns the value if this is a {@code Some} or the {@code other} value if this is a {@code None}. * <p> * Please note, that the other value is eagerly evaluated. * * @param other An alternative value * @return This value, if this Option is defined or the {@code other} value, if this Option is empty. */ @Override default T getOrElse(T other) { return isEmpty() ? other : get(); } /** * Returns this {@code Option} if it is nonempty, otherwise return the alternative. * * @param other An alternative {@code Option} * @return this {@code Option} if it is nonempty, otherwise return the alternative. */ @SuppressWarnings("unchecked") default Option<T> orElse(Option<? extends T> other) { Objects.requireNonNull(other, "other is null"); return isEmpty() ? (Option<T>) other : this; } /** * Returns this {@code Option} if it is nonempty, otherwise return the result of evaluating supplier. * * @param supplier An alternative {@code Option} supplier * @return this {@code Option} if it is nonempty, otherwise return the result of evaluating supplier. */ @SuppressWarnings("unchecked") default Option<T> orElse(Supplier<? extends Option<? extends T>> supplier) { Objects.requireNonNull(supplier, "supplier is null"); return isEmpty() ? (Option<T>) supplier.get() : this; } /** * Returns the value if this is a {@code Some}, otherwise the {@code other} value is returned, * if this is a {@code None}. * <p> * Please note, that the other value is lazily evaluated. * * @param supplier An alternative value supplier * @return This value, if this Option is defined or the {@code other} value, if this Option is empty. */ @Override default T getOrElse(Supplier<? extends T> supplier) { Objects.requireNonNull(supplier, "supplier is null"); return isEmpty() ? supplier.get() : get(); } /** * Returns the value if this is a {@code Some}, otherwise throws an exception. * * @param exceptionSupplier An exception supplier * @param <X> A throwable * @return This value, if this Option is defined, otherwise throws X * @throws X a throwable */ @Override default <X extends Throwable> T getOrElseThrow(Supplier<X> exceptionSupplier) throws X { Objects.requireNonNull(exceptionSupplier, "exceptionSupplier is null"); if (isEmpty()) { throw exceptionSupplier.get(); } else { return get(); } } /** * Returns {@code Some(value)} if this is a {@code Some} and the value satisfies the given predicate. * Otherwise {@code None} is returned. * * @param predicate A predicate which is used to test an optional value * @return {@code Some(value)} or {@code None} as specified */ default Option<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate, "predicate is null"); return isEmpty() || predicate.test(get()) ? this : none(); } /** * Maps the value to a new {@code Option} if this is a {@code Some}, otherwise returns {@code None}. * * @param mapper A mapper * @param <U> Component type of the resulting Option * @return a new {@code Option} */ @SuppressWarnings("unchecked") default <U> Option<U> flatMap(Function<? super T, ? extends Option<? extends U>> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return isEmpty() ? none() : (Option<U>) mapper.apply(get()); } /** * Maps the value and wraps it in a new {@code Some} if this is a {@code Some}, returns {@code None}. * * @param mapper A value mapper * @param <U> The new value type * @return a new {@code Some} containing the mapped value if this Option is defined, otherwise {@code None}, if this is empty. */ @Override default <U> Option<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return isEmpty() ? none() : some(mapper.apply(get())); } /** * Applies an action to this value, if this option is defined, otherwise does nothing. * * @param action An action which can be applied to an optional value * @return this {@code Option} */ @Override default Option<T> peek(Consumer<? super T> action) { Objects.requireNonNull(action, "action is null"); if (isDefined()) { action.accept(get()); } return this; } /** * Transforms this {@code Option}. * * @param f A transformation * @param <U> Type of transformation result * @return An instance of type {@code U} * @throws NullPointerException if {@code f} is null */ default <U> U transform(Function<? super Option<T>, ? extends U> f) { Objects.requireNonNull(f, "f is null"); return f.apply(this); } @Override default Iterator<T> iterator() { return isEmpty() ? Iterator.empty() : Iterator.of(get()); } @Override boolean equals(Object o); @Override int hashCode(); @Override String toString(); /** * Some represents a defined {@link Option}. It contains a value which may be null. However, to * create an Option containing null, {@code new Some(null)} has to be called. In all other cases * {@link Option#of(Object)} is sufficient. * * @param <T> The type of the optional value. * @author Daniel Dietrich */ final class Some<T> implements Option<T>, Serializable { private static final long serialVersionUID = 1L; private final T value; /** * Creates a new Some containing the given value. * * @param value A value, may be null */ private Some(T value) { this.value = value; } @Override public T get() { return value; } @Override public boolean isEmpty() { return false; } @Override public boolean equals(Object obj) { return (obj == this) || (obj instanceof Some && Objects.equals(value, ((Some<?>) obj).value)); } @Override public int hashCode() { return Objects.hashCode(value); } @Override public String stringPrefix() { return "Some"; } @Override public String toString() { return stringPrefix() + "(" + value + ")"; } } /** * None is a singleton representation of the undefined {@link Option}. * * @param <T> The type of the optional value. * @author Daniel Dietrich */ final class None<T> implements Option<T>, Serializable { private static final long serialVersionUID = 1L; /** * The singleton instance of None. */ private static final None<?> INSTANCE = new None<>(); /** * Hidden constructor. */ private None() { } @Override public T get() { throw new NoSuchElementException("No value present"); } @Override public boolean isEmpty() { return true; } @Override public boolean equals(Object o) { return o == this; } @Override public int hashCode() { return 1; } @Override public String stringPrefix() { return "None"; } @Override public String toString() { return stringPrefix(); } // -- Serializable implementation /** * Instance control for object serialization. * * @return The singleton instance of None. * @see Serializable */ private Object readResolve() { return INSTANCE; } } }