Created
March 7, 2012 17:51
-
-
Save kiritsuku/1994681 to your computer and use it in GitHub Desktop.
JDK1.8, Project Lambda, option type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.NoSuchElementException; | |
import java.util.functions.*; | |
/** | |
* Represents optional values. Instances of Option are either an instance of | |
* Some or the singleton object NONE. | |
* <p> | |
* The list dependency can be found at: https://gist.github.com/1989662 | |
* <p> | |
* ATTENTION: This code compiles only with JDK1.8 and project lambda which can | |
* be found at http://jdk8.java.net/lambda/ and is not production ready. | |
* | |
* @version 0.1 | |
* @since JDK1.6, Feb 4, 2012 | |
* @param <A> | |
* an arbitrary type which specifies the the type the Option holds. | |
*/ | |
public abstract class Option<A> { | |
/** | |
* The type NONE represents an empty Option. It does never hold a value. | |
*/ | |
@SuppressWarnings("rawtypes") | |
public static final Option NONE = new Option() { | |
@Override | |
public Object get() { | |
throw new NoSuchElementException("None.get"); | |
} | |
@Override | |
public boolean isDefined() { | |
return false; | |
} | |
@Override | |
public String toString() { | |
return "None"; | |
} | |
}; | |
/** | |
* Returns the singleton object NONE which does never hold a value. | |
* | |
* @param <B> | |
* the type which is adopted by NONE. | |
* @return the singleton object NONE. | |
*/ | |
@SuppressWarnings("unchecked") | |
public static <B> Option<B> none() { | |
return NONE; | |
} | |
/** | |
* Creates a new Some. This method guarantees that the value saved by Some is | |
* never null. | |
* | |
* @param <B> | |
* the type which is adopted by Some. | |
* @param value | |
* the parameter which is wrapped by Some. | |
* @return the parameter some wrapped by Some. | |
*/ | |
public static <B> Option<B> some(final B value) { | |
if (value == null) { | |
return none(); | |
} | |
return new Some<B>(value); | |
} | |
/** | |
* Returns the value saved by the Option type. If Option is Some the value is | |
* returned. If it is NONE, an exception is thrown. | |
* | |
* @return the saved value | |
*/ | |
public abstract A get(); | |
/** | |
* Checks whether the Option type is of type Some or not. It returns always | |
* true for some and always false for NONE. | |
* | |
* @return true when the Option is defined | |
*/ | |
public abstract boolean isDefined(); | |
/** | |
* Returns the option's value if the option is not empty, otherwise the | |
* result of evaluating the function. | |
* | |
* @param f | |
* the default expression | |
*/ | |
public A getOrElse(final Function0<A> f) { | |
return isDefined() ? get() : f.apply(); | |
} | |
/** | |
* Returns this Option's value or null if it is not defined. | |
*/ | |
public A orNull() { | |
return getOrElse(new Function0<A>() { | |
public A apply() { | |
return null; | |
} | |
}); | |
// return getOrElse(() -> null); | |
} | |
/** | |
* Returns an option which contains a mapped value. If the Option is of type | |
* Some its value is unpacked, transformed and then returned packed in a new | |
* Some. But if the Option is None nothing is transformed and None is | |
* directly returned. | |
* | |
* @param <B> | |
* the new type of the value the Option type holds | |
* @param f | |
* the function to transform the value | |
*/ | |
public <B> Option<B> map(final Mapper<A, B> f) { | |
return isDefined() ? some(f.map(get())) : Option.<B> none(); | |
} | |
/** | |
* Returns the result of applying the function to this Option's value if this | |
* Option is not empty. | |
* | |
* @param <B> | |
* the new type of the value the Option type holds | |
* @param f | |
* the function to transform the value | |
*/ | |
public <B> Option<B> flatMap(final Mapper<A, Option<B>> f) { | |
return isDefined() ? f.map(get()) : Option.<B> none(); | |
} | |
/** | |
* Returns this Option if it is not empty applying the predicate to this | |
* Option's value returns true. | |
* | |
* @param f | |
* the predicate used for testing | |
*/ | |
public Option<A> filter(final Predicate<A> f) { | |
return isDefined() && f.eval(get()) ? this : Option.<A> none(); | |
} | |
/** | |
* Apply the given procedure to the Option's value it it is not empty. | |
* | |
* @param f | |
* the procedure to apply | |
*/ | |
public void forEach(final Block<A> f) { | |
if (isDefined()) { | |
f.apply(get()); | |
} | |
} | |
/** | |
* Checks whether this Option's value is defined and applying the predicate | |
* to this Option's value returns true. | |
* | |
* @param f | |
* the predicate used for testing | |
*/ | |
public boolean exists(final Predicate<A> f) { | |
return isDefined() && f.eval(get()); | |
} | |
/** | |
* Returns this Option if it is defined, otherwise returns the result of | |
* evaluating f. | |
*/ | |
public Option<? super A> orElse(final Function0<Option<? super A>> f) { | |
if (isDefined()) { | |
return this; | |
} | |
return f.apply(); | |
} | |
/** | |
* Returns a singleton list which holds this element or an empty list if this | |
* Option is not defined. | |
*/ | |
@SuppressWarnings("unchecked") | |
public List<A> toList() { | |
return isDefined() ? List.of(get()) : List.<A> nil(); | |
} | |
} | |
/** | |
* Type Some is a wrapper for arbitrary values. The value saved by Some can | |
* never be null. | |
* | |
* @version 0.1 | |
* @since JDK1.6, Feb 4, 2012 | |
* @param <A> | |
* an arbitrary type which specifies the the type the Option holds. | |
*/ | |
final class Some<A> extends Option<A> { | |
private final A value; | |
/** | |
* Creates a new instance of Some. | |
* | |
* @param value | |
* the value | |
*/ | |
public Some(final A value) { | |
if (value == null) { | |
throw new IllegalArgumentException( | |
"value is null. Use Option.none() instead"); | |
} | |
this.value = value; | |
} | |
@Override | |
public A get() { | |
return value; | |
} | |
@Override | |
public boolean isDefined() { | |
return true; | |
} | |
@Override | |
public String toString() { | |
return "Some(" + value + ")"; | |
} | |
@Override | |
public boolean equals(Object obj) { | |
if (obj == this) { | |
return true; | |
} | |
return obj instanceof Some ? get().equals(((Some<?>) obj).get()) : false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment