【问题标题】:How can I re-throw an exception in a lambda block as from the outer block?如何从外部块重新引发 lambda 块中的异常?
【发布时间】:2015-01-12 05:49:50
【问题描述】:

使用以下代码,

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());
}

【问题讨论】:

  • 啊,没想到key(…)可能会抛出checked异常。但是my answer 也可以处理这种情况。

标签: java exception-handling lambda java-8


【解决方案1】:

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

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

【讨论】:

    【解决方案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); }
        }));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-05
      • 1970-01-01
      • 2023-03-31
      • 2013-08-13
      • 2012-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多