org.organicdesign.fp.Option Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of UncleJim Show documentation
Show all versions of UncleJim Show documentation
Immutable Clojure collections and a Transformation abstraction for Java 8+, immutably, type-safely, and with good performance. Name will change to "Paguro" in November 2016.
// Copyright (c) 2014-03-09 PlanBase Inc. & Glen Peterson
// 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 org.organicdesign.fp;
import org.organicdesign.fp.function.Function0;
import org.organicdesign.fp.function.Function1;
import java.util.Objects;
/**
Indicates presence or absence of a value (null is a valid, present value) or end-of-stream.
This is NOT a type-safe null.
@param
*/
public interface Option { // extends UnmodSortedIterable {
/** Return the value wrapped in this Option. Only safe to call this on Some. */
T get();
/** If this is Some, return the value wrapped in this Option. Otherwise, return the given value. */
T getOrElse(T t);
/** Is this Some? */
boolean isSome();
/** Pass in a function to execute if its Some and another to execute if its None. */
U patMat(Function1 has, Function0 hasNot);
// ==================================================== Static ====================================================
/** None is a singleton and this is its only instance. */
Option NONE = new None();
/** Calling this instead of referring to NONE directly can make the type infrencer happy. */
@SuppressWarnings("unchecked")
static Option none() { return NONE; }
/** Public static factory method for contructing Options. */
static Option of(T t) {
if (NONE.equals(t)) {
return none();
}
return new Some<>(t);
}
/** Construct an option, but if t is null, make it None instead of Some. */
static Option someOrNullNoneOf(T t) {
if ( (t == null) || NONE.equals(t) ) {
return none();
}
return new Some<>(t);
}
/** Represents the absence of a value */
final class None implements Option {
/** Private constructor for singleton. */
private None() {}
@Override public T get() { throw new IllegalStateException("Called get on None"); }
@Override public T getOrElse(T t) { return t; }
@Override public boolean isSome() { return false; }
//
// @Override public UnmodSortedIterator iterator() {
// return UnmodSortedIterator.empty();
// }
@Override public U patMat(Function1 has, Function0 hasNot) { return hasNot.get(); }
/** Valid, but deprecated because it's usually an error to call this in client code. */
@Deprecated // Has no effect. Darn!
@Override public int hashCode() { return 0; }
/** Valid, but deprecated because it's usually an error to call this in client code. */
@Deprecated // Has no effect. Darn!
@Override public boolean equals(Object other) { return (this == other) || (other instanceof None); }
// Defend our singleton property in the face of deserialization. Not sure this is necessary, but probably
// won't hurt.
private Object readResolve() { return NONE; }
}
/** Represents the presence of a value, even if that value is null. */
class Some implements Option {
private final T item;
private Some(T t) { item = t; }
//public static Some of(T t) { return new Option(t); }
@Override public T get() { return item; }
@Override public T getOrElse(T t) { return item; }
@Override public boolean isSome() { return true; }
//
// @Override public UnmodSortedIterator iterator() {
// return new UnmodSortedIterator() {
// private boolean hasNext = true;
// @Override public boolean hasNext() { return hasNext; }
// @Override public T next() {
// if (hasNext) {
// hasNext = false;
// return item;
// }
// throw new NoSuchElementException();
// }
// };
// }
@Override public U patMat(Function1 has, Function0 hasNot) {
return has.apply(item);
}
/** Valid, but deprecated because it's usually an error to call this in client code. */
@Deprecated // Has no effect. Darn!
@Override public int hashCode() {
// We return Integer.MIN_VALUE for null to make it different from None which always returns zero.
return item == null ? Integer.MIN_VALUE : item.hashCode();
}
/** Valid, but deprecated because it's usually an error to call this in client code. */
@Deprecated // Has no effect. Darn!
@Override public boolean equals(Object other) {
if (this == other) { return true; }
if ( !(other instanceof Option) ) { return false; }
final Option that = (Option) other;
return that.isSome() && Objects.equals(this.item, that.get());
}
}
}