综上所述,高级解决方案为未检查的函数使用特殊的包装器,如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());
下面的代码演示了消费者、供应商和函数接口。它可以很容易地扩展。本例删除了一些公共关键字。
类Try是客户端代码的端点。安全方法对于每个函数类型都可以有唯一的名称。
CheckedConsumer, CheckedSupplier和CheckedFunction是库函数的checked模拟,可以独立于Try使用
CheckedBuilder is the interface for handling exceptions in some checked function. orTry allows execute another same type function if previous was failed. handle provides exception handling including exception type filtering. The order of handlers is important. Reduce methods unsafe and rethrow rethrows last exception in the execution chain. Reduce methods orElse and orElseGet return alternate value like Optional ones if all functions failed. Also there is method suppress. CheckedWrapper is the common implementation of 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);
}
}