com.ajjpj.abase.collection.immutable.AOption Maven / Gradle / Ivy
Show all versions of a-base Show documentation
package com.ajjpj.abase.collection.immutable;
import com.ajjpj.abase.collection.ACollectionHelper;
import com.ajjpj.abase.collection.AEquality;
import com.ajjpj.abase.function.AFunction1;
import com.ajjpj.abase.function.AFunction2;
import com.ajjpj.abase.function.APredicate;
import com.ajjpj.abase.function.AStatement1;
import java.io.Serializable;
import java.util.*;
/**
* This class represents an object that may or may not be present. It is intended as a more explicit, less error prone
* replacement for using null
to represent the absence of a value.
*
* There are two flavors of AOption
: AOption.some(...)
and AOption.none()
.
* AOption.some(x)
represents the presence of a value, namely 'x', while AOption.none()
* represents 'no value'.
*
* There are two key reasons for using this class instead of using null
to encode the absence of a value.
*
* Firstly, AOption
explicitly shows in the code that a value is optional, forcing code to explicitly deal
* with that fact. A method returning a value that may or may not be present (e.g. a call to get(...)
on
* a map) can specify AOption as its return type to make that characteristic explicit.
*
* Secondly, code can operate on an AOption
regardless of whether there is a value or not (e.g. by calling
* map()
). This functional style of programming can make for code that is easier to read and less cluttered
* than having if
statements checking for the presence of values all over the place.
*
* This class was inspired by the Option
class from the Scala standard library. Thanks for the excellent
* code, Scala team!
*
* @author arno
*/
public abstract class AOption implements ACollection, Serializable {
public static AOption some(T el) {
return new ASome<>(el);
}
@SuppressWarnings("unchecked")
public static AOption none() {
return (AOption) ANone.INSTANCE;
}
public static AOption fromNullable(T nullable) {
return nullable != null ? some(nullable) : AOption.none();
}
public abstract boolean isDefined();
public boolean isEmpty() {
return !isDefined();
}
public abstract T get();
public T getOrElse(T el) {
return isDefined() ? get() : el;
}
@Override public ATraversable flatMap(AFunction1 super T, ? extends Iterable, E> f) throws E {
throw new UnsupportedOperationException("AOption can not be flattened");
}
@Override public ACollection flatten() {
throw new UnsupportedOperationException("AOption can not be flattened");
}
@Override public String mkString() {
return ACollectionHelper.mkString(this);
}
@Override public String mkString(String separator) {
return ACollectionHelper.mkString(this, separator);
}
@Override public String mkString(String prefix, String separator, String suffix) {
return ACollectionHelper.mkString(this, prefix, separator, suffix);
}
public abstract boolean equals(Object o);
public abstract int hashCode();
static class ASome extends AOption {
private final T el;
ASome(T el) {
this.el = el;
}
@Override public T get() {
return el;
}
@Override public boolean isDefined() {
return true;
}
@Override public void forEach(AStatement1 super T, E> f) throws E {
f.apply(el);
}
@Override public AOption find(APredicate super T, E> pred) throws E {
return filter(pred);
}
@Override public AOption map(AFunction1 super T, ? extends X, E> f) throws E {
return some(f.apply(el));
}
@Override public AOption filter(APredicate super T, E> pred) throws E {
if(pred.apply(el))
return this;
else
return none();
}
@Override public R foldLeft (R startValue, AFunction2 f) throws E {
return f.apply(startValue, el);
}
@Override public int size() {
return 1;
}
@Override public boolean nonEmpty() {
return true;
}
@Override public boolean forAll(APredicate super T, E> pred) throws E {
return find(pred).isDefined();
}
@Override public boolean exists(APredicate super T, E> pred) throws E {
return find(pred).isDefined();
}
@Override public AMap> groupBy(AFunction1 super T, ? extends X, E> f) throws E {
return groupBy(f, AEquality.EQUALS);
}
@Override public AMap> groupBy(AFunction1 super T, ? extends X, E> f, AEquality keyEquality) throws E { //TODO junit
final AMap> result = AHashMap.empty(keyEquality);
return result.updated(f.apply(el), this);
}
@Override public AList toList() {
return AList.nil().cons(el);
}
@Override public AHashSet toSet() {
return AHashSet.empty().added(el);
}
@Override public AHashSet toSet(AEquality equality) {
return AHashSet.empty(equality).added(el);
}
@SuppressWarnings("NullableProblems")
@Override public Iterator iterator() {
return Collections.singletonList(el).iterator();
}
@Override public String toString() {
return "AOption.some(" + el + ")";
}
@SuppressWarnings("RedundantIfStatement")
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ASome aSome = (ASome) o;
if (el != null ? !el.equals(aSome.el) : aSome.el != null) return false;
return true;
}
@Override public int hashCode() {
return el != null ? el.hashCode() : 0;
}
@Override public boolean contains(Object o) {
return AEquality.EQUALS.equals(el, o);
}
@SuppressWarnings("NullableProblems")
@Override public Object[] toArray() {
return new Object[] {el};
}
@SuppressWarnings({"NullableProblems", "SuspiciousToArrayCall"})
@Override public T1[] toArray(T1[] a) {
return Arrays.asList(el).toArray(a);
}
@Override public boolean add(T t) {
throw new UnsupportedOperationException();
}
@Override public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@SuppressWarnings({"NullableProblems", "SimplifiableIfStatement"})
@Override public boolean containsAll(Collection> c) {
if(c.isEmpty()) {
return true;
}
return c.size() == 1 && c.contains(el);
}
@SuppressWarnings("NullableProblems")
@Override public boolean addAll(Collection extends T> c) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("NullableProblems")
@Override public boolean removeAll(Collection> c) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("NullableProblems")
@Override public boolean retainAll(Collection> c) {
throw new UnsupportedOperationException();
}
@Override public void clear() {
throw new UnsupportedOperationException();
}
}
static class ANone extends AOption