All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javaslang.control.Option Maven / Gradle / Ivy

There is a newer version: 2.1.0-alpha
Show newest version
/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   JΛVΛSLΛNG
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/ \ /__\ \   Copyright 2014-2016 Javaslang, http://javaslang.io
 * /___/\_/  \_/\____/\_/  \_/\__\/__/\__\_/  \_//  \__/\_____/   Licensed under the Apache License, Version 2.0
 */
package javaslang.control;

import javaslang.API;
import javaslang.Value;
import javaslang.collection.Iterator;
import javaslang.collection.List;
import javaslang.collection.*;

import java.io.Serializable;
import java.util.*;
import java.util.function.*;

/**
 * Replacement for {@link java.util.Optional}.
 * 

* Option is a monadic container type which * represents an optional value. Instances of Option are either an instance of {@link Some} or the * singleton {@link None}. *

* Most of the API is taken from {@link java.util.Optional}. A similar type can be found in Haskell and Scala. * * @param The type of the optional value. * @author Daniel Dietrich * @since 1.0.0 */ public interface Option extends Value { /** * Creates a new {@code Option} of a given value. * * @param value A value * @param type of the value * @return {@code Some(value)} if value is not {@code null}, {@code None} otherwise */ static Option of(T value) { return (value == null) ? none() : some(value); } /** * Reduces many {@code Option}s into a single {@code Option} by transforming an * {@code Iterable>} into a {@code Option>}. 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 type of the Options * @return An {@code Option} of a {@link Seq} of results * @throws NullPointerException if {@code values} is null */ static Option> sequence(Iterable> values) { Objects.requireNonNull(values, "values is null"); List list = List.empty(); for (Option value : values) { if (value.isEmpty()) { return Option.none(); } list = list.prepend(value.get()); } return Option.some(list.reverse()); } /** * Creates a new {@code Some} of a given value. *

* The only difference to {@link Option#of(Object)} is, when called with argument {@code null}. *

     * 
     * Option.of(null);   // = None
     * Option.some(null); // = Some(null)
     * 
     * 
* * @param value A value * @param type of the value * @return {@code Some(value)} */ static Option some(T value) { return new Some<>(value); } /** * Returns the single instance of {@code None} * * @param component type * @return the single instance of {@code None} */ static Option none() { @SuppressWarnings("unchecked") final None none = (None) None.INSTANCE; return none; } /** * Return the singleton instance of {@code Some}. * * @return {@code Some} */ static Option nothing() { return Some.NOTHING; } /** * Narrows a widened {@code Option} to {@code Option} * by performing a type safe-cast. This is eligible because immutable/read-only * collections are covariant. * * @param option A {@code Option}. * @param Component type of the {@code Option}. * @return the given {@code option} instance as narrowed type {@code Option}. */ @SuppressWarnings("unchecked") static Option narrow(Option option) { return (Option) option; } /** * Creates {@code Some} of suppliers value if condition is true, or {@code None} in other case * * @param 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 Option when(boolean condition, Supplier 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 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 Option 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 type of the value * @return {@code Some(optional.get())} if value is Java {@code Optional} is present, {@code None} otherwise */ static Option ofOptional(Optional optional) { Objects.requireNonNull(optional, "optional is null"); return optional.isPresent() ? of(optional.get()) : none(); } /** * 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(); /** * Returns true, if this is {@code Some}, otherwise false, if this is {@code None}. *

* 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} is single-valued. * * @return {@code true} */ @Override default boolean isSingleValued() { return true; } @Override T get(); @Override default Option getOption() { return this; } /** * Returns the value if this is a {@code Some} or the {@code other} value if this is a {@code None}. *

* 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 orElse(Option other) { Objects.requireNonNull(other, "other is null"); return isEmpty() ? (Option) 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 orElse(Supplier> supplier) { Objects.requireNonNull(supplier, "supplier is null"); return isEmpty() ? (Option) 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}. *

* 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 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 A throwable * @return This value, if this Option is defined, otherwise throws X * @throws X a throwable */ @Override default T getOrElseThrow(Supplier 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 filter(Predicate 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 Component type of the resulting Option * @return a new {@code Option} */ @SuppressWarnings("unchecked") default Option flatMap(Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return isEmpty() ? none() : (Option) 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 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 Option map(Function 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 peek(Consumer action) { Objects.requireNonNull(action, "action is null"); if (isDefined()) { action.accept(get()); } return this; } /** * Transforms this {@code Option}. * * @param f A transformation * @param Type of transformation result * @return An instance of type {@code U} * @throws NullPointerException if {@code f} is null */ default U transform(Function, ? extends U> f) { Objects.requireNonNull(f, "f is null"); return f.apply(this); } @Override default Iterator 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 The type of the optional value. * @author Daniel Dietrich * @since 1.0.0 */ final class Some implements Option, Serializable { private static final long serialVersionUID = 1L; /** * The singleton instance of {@code Some}. */ private static final Some NOTHING = new Some<>(null); 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 The type of the optional value. * @author Daniel Dietrich * @since 1.0.0 */ final class None implements Option, 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; } } }