如何从外部块中重新抛出lambda块中的异常?

时间:2015-01-12 05:49:50

标签: java exception-handling lambda java-8

使用以下代码

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,好像方法(supplier)方法抛出它一样?

请注意,上面的代码只是一个例子。我需要key(s.get())在lambda表达式中。

void supplier(Supplier<Key> s) throws SomeCheckException {
    key(s.get());
}

2 个答案:

答案 0 :(得分:7)

你做不到。 Supplier#get()未声明抛出任何(已检查)异常。请记住,lambda表达式只是创建一个实例,它实际上并不调用目标功能接口方法。

如果您愿意,可以将已检查的异常包装在未经检查的异常中并抛出它。

答案 1 :(得分:2)

如果要以安全的方式处理已检查的异常,则需要一个帮助方法,该方法提供将异常包装到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); }
    }));