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

com.annimon.stream.Optional Maven / Gradle / Ivy

package com.annimon.stream;

import java.util.NoSuchElementException;

import com.annimon.stream.function.Consumer;
import com.annimon.stream.function.Function;
import com.annimon.stream.function.Predicate;
import com.annimon.stream.function.Supplier;

/**
 * A container object which may or may not contain a non-null value.
 * 
 * @param  the type of the inner value
 */
public class Optional {

    @SuppressWarnings("rawtypes")
    private static final Optional EMPTY = new Optional<>();

    /**
     * Returns an {@code Optional} with the specified present non-null value.
     * 
     * @param  the type of value
     * @param value  the value to be present, must be non-null
     * @return an {@code Optional}
     * @throws NullPointerException if value is null
     * @see #ofNullable(java.lang.Object) 
     */
    public static  Optional of(T value) {
        return new Optional<>(value);
    }

    /**
     * Returns an {@code Optional} with the specified value, or empty {@code Optional} if value is null.
     * 
     * @param  the type of value
     * @param value  the value which can be null
     * @return an {@code Optional}
     * @see #of(java.lang.Object) 
     */
    public static  Optional ofNullable(T value) {
        return value == null ? Optional. empty() : of(value);
    }

    /**
     * Returns an empty {@code Optional}.
     * 
     * @param  the type of value
     * @return an {@code Optional}
     */
    @SuppressWarnings("unchecked")
    public static  Optional empty() {
        return EMPTY;
    }

    private final T value;

    private Optional() {
        this.value = null;
    }

    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * Returns an inner value if present, otherwise throws {@code NoSuchElementException}.
     * 
     * @return the inner value of {@code Optional}
     * @throws NoSuchElementException if value is not present
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * Checks value present.
     * 
     * @return {@code true} if a value present, {@code false} otherwise
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
     * Invokes consumer function with value if present.
     * 
     * @param consumer  the consumer function
     */
    public void ifPresent(Consumer consumer) {
        if (value != null)
            consumer.accept(value);
    }

    /**
     * If a value is present, performs the given action with the value, otherwise performs the given empty-based action.
     *
     * @param consumer  the consumer function to be executed, if a value is present
     * @param emptyAction  the empty-based action to be performed, if no value is present
     *
     * @throws NullPointerException if a value is present and the given consumer function is null,
     *         or no value is present and the given empty-based action is null.
     */
    public void ifPresentOrElse(Consumer consumer, Runnable emptyAction) {
        if (value != null) {
            consumer.accept(value);
        } else {
            emptyAction.run();
        }
    }

    /**
     * Performs filtering on inner value if it is present.
     * 
     * @param predicate  a predicate function
     * @return this {@code Optional} if the value is present and matches predicate,
     *              otherwise an empty {@code Optional}
     */
    public Optional filter(Predicate predicate) {
        if (!isPresent())
            return this;
        return predicate.test(value) ? this : Optional. empty();
    }

    /**
     * Invokes the given mapping function on inner value if present.
     * 
     * @param  the type of result value
     * @param mapper  mapping function
     * @return an {@code Optional} with transformed value if present,
     *         otherwise an empty {@code Optional}
     * @throws NullPointerException if value is present and
     *         {@code mapper} is {@code null}
     */
    public  Optional map(Function mapper) {
        if (!isPresent())
            return empty();
        return Optional. ofNullable(mapper.apply(value));
    }

    /**
     * Invokes mapping function with {@code Optional} result if value is present.
     * 
     * @param  the type of result value
     * @param mapper  mapping function
     * @return an {@code Optional} with transformed value if present, otherwise an empty {@code Optional}
     */
    public  Optional flatMap(Function> mapper) {
        if (!isPresent())
            return empty();
        return Objects.requireNonNull(mapper.apply(value));
    }

    /**
     * Wraps a value into {@code Stream} if present, otherwise returns an empty {@code Stream}.
     *
     * @return the optional value as a {@code Stream}
     */
    public Stream stream() {
        if (!isPresent())
            return Stream.empty();
        return Stream.of(value);
    }

    /**
     * Returns inner value if present, otherwise returns {@code other}.
     * 
     * @param other  the value to be returned if inner value is not present
     * @return inner value if present, otherwise {@code other}
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * Returns inner value if present, otherwise returns value produced by supplier function.
     * 
     * @param other  supplier function that produces value if inner value is not present
     * @return inner value if present, otherwise value produced by supplier function
     */
    public T orElseGet(Supplier other) {
        return value != null ? value : other.get();
    }

    /**
     * Returns inner value if present, otherwise throws the exception provided by supplier function.
     * 
     * @param  the type of exception to be thrown
     * @param exc  supplier function that produces an exception to be thrown
     * @return inner value if present
     * @throws X if inner value is not present
     */
    public  T orElseThrow(Supplier exc) throws X {
        if (value != null)
            return value;
        else
            throw exc.get();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Optional)) {
            return false;
        }

        Optional other = (Optional) obj;
        return Objects.equals(value, other.value);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }

    @Override
    public String toString() {
        return value != null ? String.format("Optional[%s]", value) : "Optional.empty";
    }
}