package com.annimon.stream;

import com.annimon.stream.function.Consumer;
import com.annimon.stream.function.Function;
import com.annimon.stream.function.Predicate;
import java.util.NoSuchElementException;

/**
 * A container object which may or may not contain a non-null value.
 * 
 * @author aNNiMON
 */
public class Optional<T> {
    
    private static final Optional<?> EMPTY = new Optional();
    
    public static <T> Optional<T> of(T value) {
        return new Optional<T>(value);
    }
    
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? (Optional<T>) EMPTY : of(value);
    }
    
    public static <T> Optional<T> empty() {
        return (Optional<T>) EMPTY;
    }
    
    private final T value;

    private Optional() {
        this.value = null;
    }
    
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }
    
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
    
    public boolean isPresent() {
        return value != null;
    }
    
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
    
    public Optional<T> filter(Predicate<? super T> predicate) {
        if (!isPresent()) return this;
        return predicate.test(value) ? this : (Optional<T>) EMPTY;
    }
    
    public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        if (!isPresent()) return empty();
        return Optional.ofNullable(mapper.apply(value));
    }
    
    public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        if (!isPresent()) return empty();
        return Objects.requireNonNull(mapper.apply(value));
    }
    
    public T orElse(T other) {
        return value != null ? value : other;
    }
    
    @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";
    }
}

@@ -163,16 +163,62 @@
 icate;%0D%0A
+import com.annimon.stream.function.Supplier;%0D%0A
 import j
@@ -2024,32 +2024,325 @@
 ;%0D%0A    %7D%0D%0A    %0D%0A
+    public T orElseGet(Supplier%3C? extends T%3E other) %7B%0D%0A        return value != null ? value : other.get();%0D%0A    %7D%0D%0A    %0D%0A    public %3CX extends Throwable%3E T orElseThrow(Supplier%3C? extends X%3E exc) throws X %7B%0D%0A        if (value != null) return value;%0D%0A        else throw exc.get();%0D%0A    %7D%0D%0A    %0D%0A
     @Override%0D%0A 

Add orElseGet and orElseThrow to Optional