如何从外部块开始在 lambda 块中重新抛出异常?
How can I re-throw an exception in a lambda block as from the outer block?
使用以下代码,
void key(Key) throws SomeCheckedException {
}
void supplier(Supplier<Key> s) throws SomeCheckedException {
ofNullable(s).ifPresent(s -> { // |
try { // |
key(s.get()); // |
} catch (final SomeCheckedException sce) { // |
// sce is coming from key() method // |
// How can I throw sce for outer method? // --/
}
});
}
我如何抛出 sce
就像 method(supplier
) 方法抛出它一样?
请注意,以上代码只是示例。我需要 key(s.get())
位于 lambda 表达式中。
void supplier(Supplier<Key> s) throws SomeCheckException {
key(s.get());
}
你不能。 Supplier#get()
未声明抛出任何(已检查)异常。请记住,lambda 表达式只是创建一个实例,它实际上并不调用目标功能接口方法。
如果需要,可以将已检查的异常包装在未检查的异常中并抛出。
如果您想以安全的方式处理已检查的异常,您需要一个辅助方法,该方法提供将异常包装到 RuntimeException
的子类型中的便利。下面是这样一个辅助函数,它使用 Generic 的类型安全来确保只有声明的异常才会被重新抛出(除非你使用不安全的操作):
public static <E extends Throwable> void attempt(
Consumer<Function<E,RuntimeException>> action) throws E {
final class CarryException extends RuntimeException {
final E carried;
CarryException(E cause) {
super(cause);
carried=cause;
}
}
try { action.accept( CarryException::new ); }
catch(CarryException ex) { throw ex.carried; }
}
它支持任意 action
,它将接收一个函数,该函数将已检查的异常类型临时包装到 RuntimeException
。此包装将是透明的,方法 attempt
将正常完成或抛出原始检查异常 E
(或不相关的未检查异常,如果发生的话)。
所以你可以这样使用它:
public static void processIterm(Supplier<Key> s)
throws SomeCheckedException {
attempt( (Function<SomeCheckedException, RuntimeException> thrower) ->
Optional.ofNullable(s).ifPresent(nonNull -> {
try { key(nonNull.get()); } // assuming key may throw SomeCheckedException
catch(SomeCheckedException e) { throw thrower.apply(e); }
}));
}
由于嵌套操作,编译器无法自动推断异常类型。上面的代码使用 thrower
参数类型的显式声明。或者,您可以使用辅助方法的类型调用,例如
ContainingClass.<SomeCheckedException>attempt( thrower ->
Optional.ofNullable(s).ifPresent(nonNull -> {
try { key(nonNull.get()); }
catch(SomeCheckedException e) { throw thrower.apply(e); }
}));
使用以下代码,
void key(Key) throws SomeCheckedException {
}
void supplier(Supplier<Key> s) throws SomeCheckedException {
ofNullable(s).ifPresent(s -> { // |
try { // |
key(s.get()); // |
} catch (final SomeCheckedException sce) { // |
// sce is coming from key() method // |
// How can I throw sce for outer method? // --/
}
});
}
我如何抛出 sce
就像 method(supplier
) 方法抛出它一样?
请注意,以上代码只是示例。我需要 key(s.get())
位于 lambda 表达式中。
void supplier(Supplier<Key> s) throws SomeCheckException {
key(s.get());
}
你不能。 Supplier#get()
未声明抛出任何(已检查)异常。请记住,lambda 表达式只是创建一个实例,它实际上并不调用目标功能接口方法。
如果需要,可以将已检查的异常包装在未检查的异常中并抛出。
如果您想以安全的方式处理已检查的异常,您需要一个辅助方法,该方法提供将异常包装到 RuntimeException
的子类型中的便利。下面是这样一个辅助函数,它使用 Generic 的类型安全来确保只有声明的异常才会被重新抛出(除非你使用不安全的操作):
public static <E extends Throwable> void attempt(
Consumer<Function<E,RuntimeException>> action) throws E {
final class CarryException extends RuntimeException {
final E carried;
CarryException(E cause) {
super(cause);
carried=cause;
}
}
try { action.accept( CarryException::new ); }
catch(CarryException ex) { throw ex.carried; }
}
它支持任意 action
,它将接收一个函数,该函数将已检查的异常类型临时包装到 RuntimeException
。此包装将是透明的,方法 attempt
将正常完成或抛出原始检查异常 E
(或不相关的未检查异常,如果发生的话)。
所以你可以这样使用它:
public static void processIterm(Supplier<Key> s)
throws SomeCheckedException {
attempt( (Function<SomeCheckedException, RuntimeException> thrower) ->
Optional.ofNullable(s).ifPresent(nonNull -> {
try { key(nonNull.get()); } // assuming key may throw SomeCheckedException
catch(SomeCheckedException e) { throw thrower.apply(e); }
}));
}
由于嵌套操作,编译器无法自动推断异常类型。上面的代码使用 thrower
参数类型的显式声明。或者,您可以使用辅助方法的类型调用,例如
ContainingClass.<SomeCheckedException>attempt( thrower ->
Optional.ofNullable(s).ifPresent(nonNull -> {
try { key(nonNull.get()); }
catch(SomeCheckedException e) { throw thrower.apply(e); }
}));