package com.annimon.stream;
import com.annimon.stream.function.DoubleConsumer;
import com.annimon.stream.function.DoubleFunction;
import com.annimon.stream.function.DoublePredicate;
import com.annimon.stream.function.DoubleSupplier;
import com.annimon.stream.function.DoubleToIntFunction;
import com.annimon.stream.function.DoubleToLongFunction;
import com.annimon.stream.function.DoubleUnaryOperator;
import com.annimon.stream.function.Supplier;
import java.util.NoSuchElementException;
/**
* A container object which may or may not contain a {@code double} value.
*
* @since 1.1.4
* @see Optional
*/
@SuppressWarnings("WeakerAccess")
public final class OptionalDouble {
private static final OptionalDouble EMPTY = new OptionalDouble();
/**
* Returns an empty {@code OptionalDouble} instance.
*
* @return an empty {@code OptionalDouble}
*/
public static OptionalDouble empty() {
return EMPTY;
}
/**
* Returns an {@code OptionalDouble} with the specified value present.
*
* @param value the value to be present
* @return an {@code OptionalDouble} with the value present
*/
public static OptionalDouble of(double value) {
return new OptionalDouble(value);
}
private final boolean isPresent;
private final double value;
private OptionalDouble() {
this.isPresent = false;
this.value = 0;
}
private OptionalDouble(double value) {
this.isPresent = true;
this.value = value;
}
/**
* Returns an inner value if present, otherwise throws {@code NoSuchElementException}.
*
* @return the inner value of this {@code OptionalDouble}
* @throws NoSuchElementException if there is no value present
* @see OptionalDouble#isPresent()
*/
public double getAsDouble() {
if (!isPresent) {
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 isPresent;
}
/**
* Invokes consumer function with value if present, otherwise does nothing.
*
* @param consumer the consumer function to be executed if a value is present
* @throws NullPointerException if value is present and {@code consumer} is null
*/
public void ifPresent(DoubleConsumer consumer) {
if (isPresent) {
consumer.accept(value);
}
}
/**
* If a value is present, performs the given action with the value,
* otherwise performs the 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(DoubleConsumer consumer, Runnable emptyAction) {
if (isPresent) {
consumer.accept(value);
} else {
emptyAction.run();
}
}
/**
* Invokes consumer function with the value if present.
* This method same as {@code ifPresent}, but does not breaks chaining
*
* @param consumer consumer function
* @return this {@code OptionalDouble}
* @see #ifPresent(com.annimon.stream.function.DoubleConsumer)
*/
public OptionalDouble executeIfPresent(DoubleConsumer consumer) {
ifPresent(consumer);
return this;
}
/**
* Invokes action function if value is absent.
*
* @param action action that invokes if value absent
* @return this {@code OptionalDouble}
*/
public OptionalDouble executeIfAbsent(Runnable action) {
if (!isPresent()) {
action.run();
}
return this;
}
/**
* Performs filtering on inner value if present.
*
* @param predicate a predicate function
* @return this {@code OptionalDouble} if the value is present and matches predicate,
* otherwise an empty {@code OptionalDouble}
*/
public OptionalDouble filter(DoublePredicate predicate) {
if (!isPresent()) return this;
return predicate.test(value) ? this : OptionalDouble.empty();
}
/**
* Invokes the given mapping function on inner value if present.
*
* @param mapper mapping function
* @return an {@code OptionalDouble} with transformed value if present,
* otherwise an empty {@code OptionalDouble}
* @throws NullPointerException if value is present and
* {@code mapper} is {@code null}
*/
public OptionalDouble map(DoubleUnaryOperator mapper) {
if (!isPresent()) {
return empty();
}
Objects.requireNonNull(mapper);
return OptionalDouble.of(mapper.applyAsDouble(value));
}
/**
* Invokes the given mapping function on inner value if present.
*
* @param <U> 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 <U> Optional<U> mapToObj(DoubleFunction<U> mapper) {
if (!isPresent()) {
return Optional.empty();
}
Objects.requireNonNull(mapper);
return Optional.ofNullable(mapper.apply(value));
}
/**
* Invokes the given mapping function on inner value if present.
*
* @param mapper mapping function
* @return an {@code OptionalInt} with transformed value if present,
* otherwise an empty {@code OptionalInt}
* @throws NullPointerException if value is present and
* {@code mapper} is {@code null}
*/
public OptionalInt mapToInt(DoubleToIntFunction mapper) {
if (!isPresent()) {
return OptionalInt.empty();
}
Objects.requireNonNull(mapper);
return OptionalInt.of(mapper.applyAsInt(value));
}
/**
* Invokes the given mapping function on inner value if present.
*
* @param mapper mapping function
* @return an {@code OptionalLong} with transformed value if present,
* otherwise an empty {@code OptionalLong}
* @throws NullPointerException if value is present and
* {@code mapper} is {@code null}
*/
public OptionalLong mapToLong(DoubleToLongFunction mapper) {
if (!isPresent()) {
return OptionalLong.empty();
}
Objects.requireNonNull(mapper);
return OptionalLong.of(mapper.applyAsLong(value));
}
/**
* Wraps a value into {@code DoubleStream} if present,
* otherwise returns an empty {@code DoubleStream}.
*
* @return the optional value as an {@code DoubleStream}
*/
public DoubleStream stream() {
if (!isPresent()) {
return DoubleStream.empty();
}
return DoubleStream.of(value);
}
/**
* Returns current {@code OptionalDouble} if value is present, otherwise
* returns an {@code OptionalDouble} produced by supplier function.
*
* @param supplier supplier function that produces an {@code OptionalDouble} to be returned
* @return this {@code OptionalDouble} if value is present, otherwise
* an {@code OptionalDouble} produced by supplier function
* @throws NullPointerException if value is not present and
* {@code supplier} or value produced by it is {@code null}
*/
public OptionalDouble or(Supplier<OptionalDouble> supplier) {
if (isPresent()) return this;
Objects.requireNonNull(supplier);
return Objects.requireNonNull(supplier.get());
}
/**
* Returns inner value if present, otherwise returns {@code other}.
*
* @param other the value to be returned if there is no value present
* @return the value, if present, otherwise {@code other}
*/
public double orElse(double other) {
return isPresent ? value : other;
}
/**
* Returns the value if present, otherwise returns value produced by supplier function.
*
* @param other supplier function that produces value if inner value is not present
* @return the value if present otherwise the result of {@code other.getAsDouble()}
* @throws NullPointerException if value is not present and {@code other} is null
*/
public double orElseGet(DoubleSupplier other) {
return isPresent ? value : other.getAsDouble();
}
/**
* Returns the value if present, otherwise throws an exception provided by supplier function.
*
* @param <X> the type of exception to be thrown
* @param exceptionSupplier supplier function that produces an exception to be thrown
* @return inner value if present
* @throws X if inner value is not present
*/
public <X extends Throwable> double orElseThrow(Supplier<X> exceptionSupplier) throws X {
if (isPresent) {
return value;
} else {
throw exceptionSupplier.get();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof OptionalDouble)) {
return false;
}
OptionalDouble other = (OptionalDouble) obj;
return (isPresent && other.isPresent)
? Double.compare(value, other.value) == 0
: isPresent == other.isPresent;
}
@Override
public int hashCode() {
return isPresent ? Objects.hashCode(value) : 0;
}
@Override
public String toString() {
return isPresent
? String.format("OptionalDouble[%s]", value)
: "OptionalDouble.empty";
}
}