Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.vavr.control.Option Maven / Gradle / Ivy
/* ____ ______________ ________________________ __________
* \ \/ / \ \/ / __/ / \ \/ / \
* \______/___/\___\______/___/_____/___/\___\______/___/\___\
*
* Copyright 2021 Vavr, https://vavr.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.vavr.control;
import io.vavr.PartialFunction;
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}.
*
* 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.
*/
@SuppressWarnings("deprecation")
public abstract class Option implements Iterable, io.vavr.Value, Serializable {
private static final long serialVersionUID = 1L;
// sealed
private Option() {}
/**
* Creates a new {@code Option} of a given value.
*
* {@code
* // = Some(3), an Option which contains the value 3
* Option option = Option.of(3);
*
* // = None, the empty Option
* Option none = Option.of(null);
* }
*
* @param value A value
* @param type of the value
* @return {@code Some(value)} if value is not {@code null}, {@code None} otherwise
*/
public 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}.
*
* {@code
* Seq> seq = Vector.of(Option.of(1), Option.of(2), Option.of(3));
*
* // = Some(Seq(1, 2, 3))
* Option> option = Option.sequence(seq);
*
* Seq> seq = Vector.of(Option.of(1), Option.none());
*
* // = None since some elements in the Iterable are None
* Option> option = Option.sequence(seq);
* }
* @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
*/
public static Option> sequence(Iterable extends Option extends T>> values) {
Objects.requireNonNull(values, "values is null");
Vector vector = Vector.empty();
for (Option extends T> value : values) {
if (value.isEmpty()) {
return Option.none();
}
vector = vector.append(value.get());
}
return Option.some(vector);
}
/**
* Maps the values of an iterable to a sequence of mapped values into a single {@code Option} by
* transforming an {@code Iterable extends T>} into a {@code Option>}.
*
* {@code
* Function> mapper = i -> {
* if (i <= 0) {
* return Option.none();
* }
* return Option.of("a" = i.toString());
* }
*
* // = Some(Seq("a1", "a2", "a3"))
* Option> option = traverse(Vector.of(1, 2, 3), mapper);
*
* // = None
* Option> none = traverse(Vector.of(-1, 0, 1), mapper);
* }
*
* @param values An {@code Iterable} of values.
* @param mapper A mapper of values to Options
* @param The type of the given values.
* @param The mapped value type.
* @return A {@code Option} of a {@link Seq} of results.
* @throws NullPointerException if values or f is null.
*/
public static Option> traverse(Iterable extends T> values, Function super T, ? extends Option extends U>> mapper) {
Objects.requireNonNull(values, "values is null");
Objects.requireNonNull(mapper, "mapper is null");
return sequence(Iterator.ofAll(values).map(mapper));
}
/**
* Creates a new {@code Some} of a given value.
*
* The only difference to {@link Option#of(Object)} is, when called with argument {@code null}.
*
*
{@code
* // = Some(3)
* Option.some(3);
*
* // = Some(null)
* Option.some(null);
* }
*
* @param value A value
* @param type of the value
* @return {@code Some(value)}
*/
public static Option some(T value) {
return new Some<>(value);
}
/**
* Returns the single instance of {@code None}
*
* {@code
* // = None
* Option none = Option.none();
* }
*
* @param component type
* @return the single instance of {@code None}
*/
public static Option none() {
@SuppressWarnings("unchecked")
final None none = (None) None.INSTANCE;
return none;
}
/**
* Narrows a widened {@code Option extends T>} to {@code Option}
* by performing a type-safe cast. This is eligible because immutable/read-only
* collections are covariant.
*
* {@code
* Option option = Option.of(3);
* // Narrow to an Option of Number
* Option narrowed = Option.narrow(option);
* }
*
* @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")
public static Option narrow(Option extends T> option) {
return (Option) option;
}
/**
* Creates {@code Some} of suppliers value if condition is true, or {@code None} in other case
*
* {@code
* Supplier supplier = () -> "supplied";
*
* // = Some("supplied")
* Option supplied = Option.when(true, supplier);
*
* // = None
* Option none = Option.when(false, supplier);
* }
*
* @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
*/
public static Option 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
*
* {@code
* // = Some(5)
* Option option = Option.when(true, 5);
*
* // = None
* Option none = Option.when(false, 5);
* }
*
* @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
*/
public static Option when(boolean condition, T value) {
return condition ? some(value) : none();
}
/**
* Wraps a Java Optional to a new Option
*
* {@code
* Optional optional = Optional.ofNullable("value");
*
* // Make a Some("value") from an Optional
* Option option = Option.ofOptional(optional);
*
* Optional empty = Optional.empty();
*
* // Make a None from an empty Optional
* Option none = Option.ofOptional(empty);
* }
*
* @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
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public static Option ofOptional(Optional extends T> optional) {
Objects.requireNonNull(optional, "optional is null");
return optional.>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}.
*
* {@code
* partialFunction.isDefinedAt(value)
* }
*
* If the element makes it through that filter, the mapped instance is wrapped in {@code Option}
*
* {@code
* R newValue = partialFunction.apply(value)
* }
*
*
* @param partialFunction A function that is not necessarily defined on value of this option.
* @param The new value type
* @return A new {@code Option} instance containing value of type {@code R}
* @throws NullPointerException if {@code partialFunction} is null
*/
public final Option collect(PartialFunction super T, ? extends R> partialFunction) {
Objects.requireNonNull(partialFunction, "partialFunction is null");
return flatMap(partialFunction.lift());
}
/**
* Returns true, if this is {@code None}, otherwise false, if this is {@code Some}.
*
* {@code
* // Prints "false"
* System.out.println(Option.of(10).isEmpty());
*
* // Prints "true"
* System.out.println(Option.none().isEmpty());
* }
*
* @return true, if this {@code Option} is empty, false otherwise
*/
@Override
public abstract boolean isEmpty();
/**
* Runs a Java Runnable passed as parameter if this {@code Option} is empty.
*
* {@code
* Runnable print = () -> System.out.println("Option is empty");
*
* // Prints nothing
* Option.of("value").onEmpty(print);
*
* // Prints "Option is empty"
* Option.none().onEmpty(print);
* }
*
* @param action a given Runnable to be run
* @return this {@code Option}
*/
public final Option onEmpty(Runnable action) {
Objects.requireNonNull(action, "action is null");
if (isEmpty()) {
action.run();
}
return this;
}
/**
* An {@code Option}'s value is computed synchronously.
*
* {@code
* // Prints "false"
* System.out.println(Option.of(1).isAsync());
*
* // Prints "false"
* System.out.println(Option.none().isAsync());
* }
*
* @return false
*/
@Override
public final boolean isAsync() {
return false;
}
/**
* 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.
*
*
{@code
* // Prints "true"
* System.out.println(Option.of(10).isDefined());
*
* // Prints "false"
* System.out.println(Option.none().isDefined());
*
* // Prints "true
* System.out.println(Option.of(null).isDefined());
* }
*
* @return true, if this {@code Option} has a defined value, false otherwise
*/
public final boolean isDefined() {
return !isEmpty();
}
/**
* An {@code Option}'s value is computed eagerly.
*
* {@code
* // Prints "false"
* System.out.println(Option.of(3.14).isLazy());
*
* // Prints "false"
* System.out.println(Option.none().isLazy());
* }
*
* @return false
*/
@Override
public final boolean isLazy() {
return false;
}
/**
* An {@code Option} is single-valued.
*
* {@code
* // Prints "true"
* System.out.println(Option.of("value").isSingleValued());
*
* // Prints "true"
* System.out.println(Option.none().isSingleValued());
* }
*
* @return {@code true}
*/
@Override
public final boolean isSingleValued() {
return true;
}
/**
* Gets the value if this is a {@code Some} or throws if this is a {@code None}.
*
* {@code
* // Prints "57"
* System.out.println(Option.of(57).get());
*
* // Throws a NoSuchElementException
* Option.none().get();
* }
*
* @return the value
* @throws NoSuchElementException if this is a {@code None}.
*/
@Override
public abstract T get();
/**
* 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.
*
*
{@code
* // Prints "Hello"
* System.out.println(Option.of("Hello").getOrElse("World"));
*
* // Prints "World"
* Option.none().getOrElse("World");
* }
*
* @param other An alternative value
* @return This value, if this Option is defined or the {@code other} value, if this Option is empty.
*/
@Override
public final T getOrElse(T other) {
return isEmpty() ? other : get();
}
/**
* Returns this {@code Option} if it is nonempty, otherwise return the alternative.
*
* {@code
* Option other = Option.of("Other");
*
* // = Some("Hello World")
* Option.of("Hello World").orElse(other);
*
* // = Some("Other")
* Option.none().orElse(other);
* }
*
* @param other An alternative {@code Option}
* @return this {@code Option} if it is nonempty, otherwise return the alternative.
*/
@SuppressWarnings("unchecked")
public final Option orElse(Option extends T> 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.
*
* {@code
* Supplier> supplier = () -> Option.of(5);
*
* // = Some(2)
* Option.of(2).orElse(supplier);
*
* // = Some(5)
* Option.none().orElse(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")
public final Option orElse(Supplier extends Option extends T>> supplier) {
Objects.requireNonNull(supplier, "supplier is null");
return isEmpty() ? (Option) supplier.get() : this;
}
/**
* Returns this {@code Option} if this is defined, or {@code null} if it is empty.
*
* {@code
* // = Some("Hello World")
* Option.of("Hello World").orNull();
*
* // = null
* Option.none().orNull();
* }
*
* @return this value if it is defined, or {@code null} if it is empty.
*/
public final T orNull() {
return isEmpty() ? null : get();
}
/**
* Returns the value if this is a {@code Some}, otherwise {@code supplier.get()} is returned.
*
* Please note, that the alternate value is lazily evaluated.
*
*
{@code
* Supplier supplier = () -> 5.342;
*
* // = 1.2
* Option.of(1.2).getOrElse(supplier);
*
* // = 5.342
* Option.none().getOrElse(supplier);
* }
*
* @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
public final 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.
*
* {@code
* Supplier supplier = () -> new RuntimeException();
*
* // = 12
* Option.of(12).getOrElseThrow(supplier);
*
* // throws RuntimeException
* Option.none().getOrElseThrow(supplier);
* }
*
* @param exceptionSupplier An exception supplier
* @param A throwable
* @return This value, if this Option is defined, otherwise throws X
* @throws X a throwable
*/
@Override
public final 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.
*
* {@code
* Predicate isLessThanTen = i -> i < 10;
*
* // = Some(8)
* Option.some(8).filter(isLessThanTen);
*
* // = None
* Option.some(12).filter(isLessThanTen);
*
* // = None
* Option.none().filter(isLessThanTen);
* }
*
* @param predicate A predicate which is used to test an optional value
* @return {@code Some(value)} or {@code None} as specified
*/
public final Option filter(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return isEmpty() || predicate.test(get()) ? this : none();
}
/**
* Returns {@code Some(value)} if this is a {@code Some} and the value not satisfies the given predicate.
* Otherwise {@code None} is returned.
*
* {@code
* Predicate isEven = i -> (i & 1) == 0;
*
* // = Some(5)
* Option.some(5).filterNot(isEven);
*
* // = None
* Option.some(12).filterNot(isEven);
*
* // = None
* Option.none().filterNot(isEven);
* }
*
* @param predicate A predicate which is used to test an optional value
* @return {@code Some(value)} or {@code None} as specified
*/
public final Option filterNot(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return filter(predicate.negate());
}
/**
* Maps the value to a new {@code Option} if this is a {@code Some}, otherwise returns {@code None}.
*
* {@code
* Function> mapper = i -> i < 10 ? Option.of(i * 2) : Option.none();
*
* // = Some(14)
* Option.of(7).flatMap(mapper);
*
* // = None
* Option.of(11).flatMap(mapper);
*
* // = None
* Option.none().flatMap(mapper);
* }
*
* @param mapper A mapper
* @param Component type of the resulting Option
* @return a new {@code Option}
*/
@SuppressWarnings("unchecked")
public final Option flatMap(Function super T, ? extends Option extends U>> 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}, otherwise returns a {@code None}.
*
* {@code
* Function mapper = s -> s + " World!";
*
* // = Some("Hello World!")
* Option.of("Hello").map(mapper);
*
* // = None
* Option.none().map(mapper);
* }
*
* @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
public final Option map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return isEmpty() ? none() : some(mapper.apply(get()));
}
/**
* Folds either the {@code None} or the {@code Some} side of the Option value.
*
* {@code
* Supplier ifNone = () -> 3.14;
* Function mapper = s -> Double.valueOf(s) + 0.98;
*
* // = Some(4.98)
* Option.of("4").fold(ifNone, mapper);
*
* // = Some(3.14)
* Option.none().fold(ifNone, mapper);
* }
*
* @param ifNone maps the left value if this is a None
* @param f maps the value if this is a Some
* @param type of the folded value
* @return A value of type U
*/
public final U fold(Supplier extends U> ifNone, Function super T, ? extends U> f) {
return this.map(f).getOrElse(ifNone);
}
/**
* Performs the given {@code noneAction} if this option is not defined.
* Performs the given {@code someAction} to this value, if this option is defined.
*
* @param noneAction The action that will be performed on the left element
* @param someAction The action that will be performed on the right element
* @return this instance
*/
public final Option peek(Runnable noneAction, Consumer super T> someAction) {
Objects.requireNonNull(noneAction, "noneAction is null");
Objects.requireNonNull(someAction, "someAction is null");
if (isEmpty()) {
noneAction.run();
} else {
someAction.accept(get());
}
return this;
}
/**
* Applies an action to this value, if this option is defined, otherwise does nothing.
*
* {@code
* Consumer print = i -> System.out.println(i);
*
* // Prints 5 and creates Some(8)
* Option.of(5).peek(print).map(i -> i + 3);
*
* // Does not print anything
* Option.none().peek(print);
* }
*
* @param action An action which can be applied to an optional value
* @return this {@code Option}
*/
@Override
public final Option peek(Consumer super T> action) {
Objects.requireNonNull(action, "action is null");
if (isDefined()) {
action.accept(get());
}
return this;
}
/**
* Transforms this {@code Option}.
*
* {@code
* Function, String> f = o -> o.getOrElse(3).toString().concat("-transformed"));
*
* // Prints "1-transformed"
* System.out.println(Option.of(1).transform(f));
*
* // Prints "3-transformed"
* System.out.println(Option.none().transform(f));
* }
*
* @param f A transformation
* @param Type of transformation result
* @return An instance of type {@code U}
* @throws NullPointerException if {@code f} is null
*/
public final U transform(Function super Option, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return f.apply(this);
}
@Override
public final Iterator iterator() {
return isEmpty() ? Iterator.empty() : Iterator.of(get());
}
/**
* 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.
* @deprecated will be removed from the public API
*/
@Deprecated
public static final class Some extends Option implements 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 The type of the optional value.
* @deprecated will be removed from the public API
*/
@Deprecated
public static final class None extends Option implements 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;
}
}
}