总结上述高级解决方案中的注释,是对带有API之类构建器的未经检查的函数使用特殊的包装,该API提供恢复,重新抛出和抑制。
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(Try.<String, Class<?>>safe(Class::forName)
.handle(System.out::println)
.unsafe())
.collect(toList());
下面的代码针对Consumer,Supplier和Function接口进行了演示。它可以轻松扩展。在此示例中,删除了一些公共关键字。
Try类是客户端代码的端点。对于每种函数类型,安全方法可能具有唯一的名称。
CheckedConsumer,CheckedSupplier和CheckedFunction是lib函数的已检查类似物,可以独立于Try使用
CheckedBuilder是用于处理某些选中函数中的异常的接口。如果上一个失败,则orTry允许执行另一个相同类型的函数。handle提供异常处理,包括异常类型过滤。处理程序的顺序很重要。减少方法不安全,然后重新抛出,重新抛出执行链中的最后一个异常。如果所有函数均失败,则Reduce方法的orElse和orElseGet返回替代值,例如Optional。也有方法抑制。 CheckedWrapper是CheckedBuilder的常见实现。
final class Try {
public static <T> CheckedBuilder<Supplier<T>, CheckedSupplier<T>, T>
safe(CheckedSupplier<T> supplier) {
return new CheckedWrapper<>(supplier,
(current, next, handler, orResult) -> () -> {
try { return current.get(); } catch (Exception ex) {
handler.accept(ex);
return next.isPresent() ? next.get().get() : orResult.apply(ex);
}
});
}
public static <T> Supplier<T> unsafe(CheckedSupplier<T> supplier) {
return supplier;
}
public static <T> CheckedBuilder<Consumer<T>, CheckedConsumer<T>, Void>
safe(CheckedConsumer<T> consumer) {
return new CheckedWrapper<>(consumer,
(current, next, handler, orResult) -> t -> {
try { current.accept(t); } catch (Exception ex) {
handler.accept(ex);
if (next.isPresent()) {
next.get().accept(t);
} else {
orResult.apply(ex);
}
}
});
}
public static <T> Consumer<T> unsafe(CheckedConsumer<T> consumer) {
return consumer;
}
public static <T, R> CheckedBuilder<Function<T, R>, CheckedFunction<T, R>, R>
safe(CheckedFunction<T, R> function) {
return new CheckedWrapper<>(function,
(current, next, handler, orResult) -> t -> {
try { return current.applyUnsafe(t); } catch (Exception ex) {
handler.accept(ex);
return next.isPresent() ? next.get().apply(t) : orResult.apply(ex);
}
});
}
public static <T, R> Function<T, R> unsafe(CheckedFunction<T, R> function) {
return function;
}
@SuppressWarnings ("unchecked")
static <T, E extends Throwable> T throwAsUnchecked(Throwable exception) throws E {
throw (E) exception;
}
}
@FunctionalInterface interface CheckedConsumer<T> extends Consumer<T> {
void acceptUnsafe(T t) throws Exception;
@Override default void accept(T t) {
try { acceptUnsafe(t); } catch (Exception ex) {
Try.throwAsUnchecked(ex);
}
}
}
@FunctionalInterface interface CheckedFunction<T, R> extends Function<T, R> {
R applyUnsafe(T t) throws Exception;
@Override default R apply(T t) {
try { return applyUnsafe(t); } catch (Exception ex) {
return Try.throwAsUnchecked(ex);
}
}
}
@FunctionalInterface interface CheckedSupplier<T> extends Supplier<T> {
T getUnsafe() throws Exception;
@Override default T get() {
try { return getUnsafe(); } catch (Exception ex) {
return Try.throwAsUnchecked(ex);
}
}
}
interface ReduceFunction<TSafe, TUnsafe, R> {
TSafe wrap(TUnsafe current, Optional<TSafe> next,
Consumer<Throwable> handler, Function<Throwable, R> orResult);
}
interface CheckedBuilder<TSafe, TUnsafe, R> {
CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next);
CheckedBuilder<TSafe, TUnsafe, R> handle(Consumer<Throwable> handler);
<E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handle(
Class<E> exceptionType, Consumer<E> handler);
CheckedBuilder<TSafe, TUnsafe, R> handleLast(Consumer<Throwable> handler);
<E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handleLast(
Class<E> exceptionType, Consumer<? super E> handler);
TSafe unsafe();
TSafe rethrow(Function<Throwable, Exception> transformer);
TSafe suppress();
TSafe orElse(R value);
TSafe orElseGet(Supplier<R> valueProvider);
}
final class CheckedWrapper<TSafe, TUnsafe, R>
implements CheckedBuilder<TSafe, TUnsafe, R> {
private final TUnsafe function;
private final ReduceFunction<TSafe, TUnsafe, R> reduceFunction;
private final CheckedWrapper<TSafe, TUnsafe, R> root;
private CheckedWrapper<TSafe, TUnsafe, R> next;
private Consumer<Throwable> handlers = ex -> { };
private Consumer<Throwable> lastHandlers = ex -> { };
CheckedWrapper(TUnsafe function,
ReduceFunction<TSafe, TUnsafe, R> reduceFunction) {
this.function = function;
this.reduceFunction = reduceFunction;
this.root = this;
}
private CheckedWrapper(TUnsafe function,
CheckedWrapper<TSafe, TUnsafe, R> prev) {
this.function = function;
this.reduceFunction = prev.reduceFunction;
this.root = prev.root;
prev.next = this;
}
@Override public CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next) {
return new CheckedWrapper<>(next, this);
}
@Override public CheckedBuilder<TSafe, TUnsafe, R> handle(
Consumer<Throwable> handler) {
handlers = handlers.andThen(handler);
return this;
}
@Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R>
handle(Class<E> exceptionType, Consumer<E> handler) {
handlers = handlers.andThen(ex -> {
if (exceptionType.isInstance(ex)) {
handler.accept(exceptionType.cast(ex));
}
});
return this;
}
@Override public CheckedBuilder<TSafe, TUnsafe, R> handleLast(
Consumer<Throwable> handler) {
lastHandlers = lastHandlers.andThen(handler);
return this;
}
@Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R>
handleLast(Class<E> exceptionType, Consumer<? super E> handler) {
lastHandlers = lastHandlers.andThen(ex -> {
if (exceptionType.isInstance(ex)) {
handler.accept(exceptionType.cast(ex));
}
});
return this;
}
@Override public TSafe unsafe() {
return root.reduce(ex -> Try.throwAsUnchecked(ex));
}
@Override
public TSafe rethrow(Function<Throwable, Exception> transformer) {
return root.reduce(ex -> Try.throwAsUnchecked(transformer.apply(ex)));
}
@Override public TSafe suppress() {
return root.reduce(ex -> null);
}
@Override public TSafe orElse(R value) {
return root.reduce(ex -> value);
}
@Override public TSafe orElseGet(Supplier<R> valueProvider) {
Objects.requireNonNull(valueProvider);
return root.reduce(ex -> valueProvider.get());
}
private TSafe reduce(Function<Throwable, R> orResult) {
return reduceFunction.wrap(function,
Optional.ofNullable(next).map(p -> p.reduce(orResult)),
this::handle, orResult);
}
private void handle(Throwable ex) {
for (CheckedWrapper<TSafe, TUnsafe, R> current = this;
current != null;
current = current.next) {
current.handlers.accept(ex);
}
lastHandlers.accept(ex);
}
}