Skip to content

Instantly share code, notes, and snippets.

@fsarradin
Forked from anonymous/Option.java
Created January 4, 2013 17:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fsarradin/4454484 to your computer and use it in GitHub Desktop.
Save fsarradin/4454484 to your computer and use it in GitHub Desktop.
package my.util;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.Function;
public abstract class Option<T> implements Iterable<T> {
private Option() {
// idiom that declares Option final for outer classes only
// equivalent to keyword *sealed* from Scala
}
public abstract boolean isEmpty();
public abstract T get();
public <U> Option<U> map(Function<? super T, U> function) {
if (isEmpty()) {
return None();
}
return Some(function.apply(get()));
}
public <U> Option<U> flatMap(Function<? super T, Option<U>> function) {
if (isEmpty()) {
return None();
}
return function.apply(get());
}
public static <U> Option<U> Some(U value) {
return new Some<U>() {
@Override
public U get() {
return value;
}
};
}
public static <U> Option<U> None() {
return (Option<U>) NONE;
}
public List<T> toList() {
if (isEmpty()) {
return Collections.emptyList();
}
return Collections.singletonList(get());
}
@Override
public Iterator<T> iterator() {
return toList().iterator();
}
private static final Option<?> NONE = new Option<Object>() {
@Override
public boolean isEmpty() {
return true;
}
@Override
public Object get() {
throw new NoSuchElementException();
}
};
private static abstract class Some<U> extends Option<U> {
@Override
public boolean isEmpty() {
return false;
}
}
}
@fsarradin
Copy link
Author

The implementation here is not complete. You can add operations like getOrElse or filter.

Here are two uses of this class.

Suppose that service1.getInteger() and service2.getInteger() both return Option.

Option<Integer> result = (Option<Integer>) service1.getInteger()
        .flatMap(x -> service2.getInteger()
                .map(y -> x + y));

If you get 1 from service1 and 2 from service2, then:

result.isEmpty(); // false
result.get(); // 3

If one of service1 or service2 return None, then:

result.isEmpty(); // true

Here is another use:

int result = 0;

for (int x : service1.getInteger()) {
    for (int y : Some(2)) {
        result = x + y;
    }
}

If you get 1 from service1 and 2 from service2, then result == 3.

If one of service1 or service2 return None, then result == 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment