All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ajjpj.afoundation.collection.immutable.AOption Maven / Gradle / Ivy

The newest version!
package com.ajjpj.afoundation.collection.immutable;

import com.ajjpj.afoundation.collection.ACollectionHelper;
import com.ajjpj.afoundation.collection.AEquality;
import com.ajjpj.afoundation.function.*;

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 { /** * @return a 'some' filled with the literal passed in as a parameter */ public static AOption some(T el) { return new ASome<>(el); } /** * @return the 'none' */ @SuppressWarnings("unchecked") public static AOption none() { return (AOption) ANone.INSTANCE; } /** * This is a convenience method that creates an AOption based on Java conventions. * * @return 'none()' if the parameter is null, 'some(nullable)' otherwise */ public static AOption fromNullable(T nullable) { return nullable != null ? some(nullable) : AOption.none(); } /** * @return true if this AOption holds a value */ public abstract boolean isDefined(); /** * @return true if this option does not hold a value */ public boolean isEmpty() { return !isDefined(); } /** * @return the element held in this AOption if there is one; otherwise, a NoSuchElementException is thrown */ public abstract T get(); /** * @return the element held in this AOption if there is one, and the default element passed in as parameter otherwise */ public abstract T getOrElse (T defaultValue); /** * @return the element held in this AOption if there is one, and the result of evaluating the function passed in otherwise. The function is * guaranteed to be evaluated only if this AOption is empty. */ public abstract T getOrElseEval (AFunction0 producer) throws E; /** * This method returns the element contained in this AOption if it is defined. Otherwise, it evaluates the function passed in and throws the exception * returned by that function. The function is guaranteed to be evaluated only if this AOption is empty. */ public abstract T getOrElseThrow (AFunction0NoThrow producer) throws E; @Override public abstract AOption map(AFunction1 f) throws E; @Override public ACollection flatMap(AFunction1, 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(); @Override public Collection asJavaUtilCollection () { return new AbstractCollection () { @SuppressWarnings ("NullableProblems") @Override public Iterator iterator () { return AOption.this.iterator (); } @Override public int size () { return iterator ().hasNext () ? 1 : 0; } }; } static class ASome extends AOption { private final T el; ASome(T el) { this.el = el; } @Override public T get() { return el; } @Override public T getOrElse (T defaultValue) { return el; } @Override public T getOrElseEval (AFunction0 producer) throws E { return el; } @Override public T getOrElseThrow (AFunction0NoThrow producer) throws E { return el; } @Override public boolean isDefined() { return true; } @Override public ACollection clear () { return none (); } @Override public void foreach(AStatement1 f) throws E { f.apply(el); } @Override public AOption find(APredicate pred) throws E { return filter(pred); } @Override public AOption map(AFunction1 f) throws E { return some (f.apply (el)); } @Override public ACollection collect (APartialFunction pf) throws E { if (pf.isDefinedAt (el)) { return some (pf.apply (el)); } else { return none(); } } @Override public AOption filter(APredicate 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 pred) throws E { return find(pred).isDefined(); } @Override public boolean exists(APredicate pred) throws E { return find(pred).isDefined(); } @Override public AMap> groupBy(AFunction1 f) throws E { return groupBy(f, AEquality.EQUALS); } @Override public AMap> groupBy(AFunction1 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 ASet toSet() { return AHashSet.empty ().added(el); } @Override public ASet 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 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 { public static final ANone INSTANCE = new ANone(); private ANone() {} private Object readResolve() { return INSTANCE; } @Override public ACollection clear () { return this; } @Override public Object get() { throw new NoSuchElementException("no value for ANone"); } @Override public Object getOrElse (Object defaultValue) { return defaultValue; } @Override public Object getOrElseEval (AFunction0 producer) throws E { return producer.apply (); } @Override public Object getOrElseThrow (AFunction0NoThrow producer) throws E { throw producer.apply (); } @Override public boolean isDefined() { return false; } @Override public void foreach(AStatement1 f) { // nothing to be done } @Override public AOption find(APredicate pred) throws E { return none(); } @Override public AOption map(AFunction1 f) { return none(); } @Override public ACollection collect (APartialFunction pf) throws E { return none(); } @Override public R foldLeft (R startValue, AFunction2 f) throws E { return startValue; } @Override public AOption filter(APredicate pred) { return none(); } @Override public boolean nonEmpty() { return false; } @Override public int size() { return 0; } @Override public boolean forAll(APredicate pred) throws E { return true; } @Override public boolean exists(APredicate pred) throws E { return false; } @Override public AMap> groupBy(AFunction1 f) throws E { return AHashMap.empty(); //TODO junit } @Override public AMap> groupBy(AFunction1 f, AEquality keyEquality) throws E { return AHashMap.empty(keyEquality); //TODO junit } @Override public AList toList() { return AList.nil(); } @Override public ASet toSet() { return AHashSet.empty (); } @Override public ASet toSet(AEquality equality) { return AHashSet.empty (equality); } @SuppressWarnings("NullableProblems") @Override public Iterator iterator() { return Collections.emptyList().iterator(); } @Override public String toString() { return "AOption.none()"; } @Override public boolean equals(Object o) { return o == this; } @Override public int hashCode() { return 0; } @Override public boolean contains(Object o) { return false; } // @SuppressWarnings("NullableProblems") // @Override public Object[] toArray() { // return new Object[0]; // } // // @SuppressWarnings("NullableProblems") // @Override public T[] toArray(T[] a) { // if(a.length > 0) { // a[0] = null; // } // return a; // } // // @Override // public boolean add(Object o) { // throw new UnsupportedOperationException(); // } // // @Override public boolean remove(Object o) { // throw new UnsupportedOperationException(); // } // // @SuppressWarnings("NullableProblems") // @Override public boolean containsAll(Collection c) { // return c.isEmpty(); // } // // @SuppressWarnings("NullableProblems") // @Override public boolean addAll(Collection 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(); // } } }