下面提供了Exceptional类的完整代码。它有一个相当大的API,它是可选API的纯扩展,所以它可以是任何现有代码中的一个替代,除了它不是最后的可选类的子类型。类可以看作与
Try monad具有相同的关系,可选是与Maybe monad:它从它吸取灵感,但适应Java成语(如实际抛出异常,甚至从非终端操作) 。
这些是课程遵循的一些关键指导方针:
>相对于monadic方法,不忽略Java的异常机制;
>而是它减轻了异常和高阶函数之间的阻抗失配;
>异常处理不是静态类型安全的(由于偷偷摸摸的抛出),但在运行时总是安全的(除非明确请求,否则不会收到异常)。
类试图覆盖所有典型的处理异常的方法:
>恢复一些提供替代值的处理代码;
> flatRecover,类似于flatMap,允许返回一个新的异常实例,该实例将被展开并且适当地更新当前实例的状态;
>传播异常,将其从Exceptional表达式中抛出并使propagate调用声明此异常类型;
>将其传播到另一个异常(翻译);
>处理它,导致一个空异常;
>作为一种特殊的处理方式,用一个空的处理程序块来吞下它。
传播方法允许选择性地挑选哪些被检查的异常他想从他的代码暴露。在终端操作被调用时保持未处理的异常(例如get)将被狡猾地抛出而没有声明。这通常被认为是一种高级和危险的方法,但是经常被采用作为一种方式,以在某种程度上减轻检查异常与不声明它们的lambda形状的组合的麻烦。异常类希望提供一个更清洁和更有选择性的替代鬼祟。
/*
* Copyright (c) 2015, Marko Topolnik. All Rights Reserved.
*
* 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.
*/
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public final class Exceptional
{
private final T value;
private final Throwable exception;
private Exceptional(T value, Throwable exc) {
this.value = value;
this.exception = exc;
}
public static Exceptional empty() {
return new Exceptional<>(null, null);
}
public static Exceptional ofNullable(T value) {
return value != null ? of(value) : empty();
}
public static Exceptional of(T value) {
return new Exceptional<>(Objects.requireNonNull(value), null);
}
public static Exceptional ofNullableException(Throwable exception) {
return exception != null? new Exceptional<>(null, exception) : empty();
}
public static Exceptional ofException(Throwable exception) {
return new Exceptional<>(null, Objects.requireNonNull(exception));
}
public static Exceptional from(TrySupplier supplier) {
try {
return ofNullable(supplier.tryGet());
} catch (Throwable t) {
return new Exceptional<>(null, t);
}
}
public static Exceptional fromVoid(TryRunnable task) {
try {
task.run();
return new Exceptional<>(null, null);
} catch (Throwable t) {
return new Exceptional<>(null, t);
}
}
public static Consumer super E> swallow() {
return e -> {};
}
public T get() {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
throw new NoSuchElementException("No value present");
}
public T orElse(T other) {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
return other;
}
public T orElseGet(Supplier extends T> other) {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
return other.get();
}
public Exceptional map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (value == null) return new Exceptional<>(null, exception);
final U u;
try {
u = mapper.apply(value);
} catch (Throwable exc) {
return new Exceptional<>(null, exc);
}
return ofNullable(u);
}
public Exceptional flatMap(Function super T, Exceptional> mapper) {
Objects.requireNonNull(mapper);
return value != null ? Objects.requireNonNull(mapper.apply(value)) : empty();
}
public Exceptional filter(Predicate super T> predicate) {
Objects.requireNonNull(predicate);
if (value == null) return this;
final boolean b;
try {
b = predicate.test(value);
} catch (Throwable t) {
return ofException(t);
}
return b ? this : empty();
}
public Exceptional recover(
Class extends X> excType, Function super X, T> mapper)
{
Objects.requireNonNull(mapper);
return excType.isInstance(exception) ? ofNullable(mapper.apply(excType.cast(exception))) : this;
}
public Exceptional recover(
Iterable> excTypes, Function super X, T> mapper)
{
Objects.requireNonNull(mapper);
for (Class extends X> excType : excTypes)
if (excType.isInstance(exception))
return ofNullable(mapper.apply(excType.cast(exception)));
return this;
}
public Exceptional flatRecover(
Class extends X> excType, Function super X, Exceptional> mapper)
{
Objects.requireNonNull(mapper);
return excType.isInstance(exception) ? Objects.requireNonNull(mapper.apply(excType.cast(exception))) : this;
}
public Exceptional flatRecover(
Iterable> excTypes, Function super X, Exceptional> mapper)
{
Objects.requireNonNull(mapper);
for (Class extends X> c : excTypes)
if (c.isInstance(exception))
return Objects.requireNonNull(mapper.apply(c.cast(exception)));
return this;
}
public Exceptional propagate(Class excType) throws E {
if (excType.isInstance(exception))
throw excType.cast(exception);
return this;
}
public Exceptional propagate(Iterable> excTypes) throws E {
for (Class extends E> excType : excTypes)
if (excType.isInstance(exception))
throw excType.cast(exception);
return this;
}
public Exceptional propagate(
Class excType, Function super E, ? extends F> translator)
throws F
{
if (excType.isInstance(exception))
throw translator.apply(excType.cast(exception));
return this;
}
public Exceptional propagate(
Iterable> excTypes, Function super E, ? extends F> translator)
throws F
{
for (Class extends E> excType : excTypes)
if (excType.isInstance(exception))
throw translator.apply(excType.cast(exception));
return this;
}
public Exceptional handle(Class excType, Consumer super E> action) {
if (excType.isInstance(exception)) {
action.accept(excType.cast(exception));
return empty();
}
return this;
}
public Exceptional handle(Iterable> excTypes, Consumer super E> action) {
for (Class extends E> excType : excTypes)
if (excType.isInstance(exception)) {
action.accept(excType.cast(exception));
return empty();
}
return this;
}
public T orElseThrow(Supplier extends X> exceptionSupplier) throws X {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
throw exceptionSupplier.get();
}
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer super T> consumer) {
if (value != null)
consumer.accept(value);
if (exception != null) sneakyThrow(exception);
}
public boolean isException() {
return exception != null;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
return obj instanceof Exceptional && Objects.equals(value, ((Exceptional)obj).value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@SuppressWarnings("unchecked")
private static void sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
@FunctionalInterface
public interface TrySupplier {
T tryGet() throws Throwable;
}
@FunctionalInterface
public interface TryRunnable {
void run() throws Throwable;
}