高度なソリューションの上のコメントを要約すると、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は、Tryとは独立して使用できるlib関数のチェック済みアナログです。
CheckedBuilderは、いくつかのチェックされた関数で例外を処理するためのインターフェースです。orTryは、前が失敗した場合に別の同じタイプの関数を実行できるようにします。handleは、例外タイプフィルタリングを含む例外処理を提供します。ハンドラーの順序は重要です。安全でないメソッドを減らし、再スローして実行チェーンの最後の例外を再スローします。すべての関数が失敗した場合、reduceメソッドorElseおよびorElseGetは、オプションの値のような代替値を返します。また、メソッドsuppressもあります。 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);
}
}