Java 8:我如何使用stream中的exception抛出方法?

假设我有一个类和一个方法

class A { void foo() throws Exception() { ... } } 

现在我想为每个由stream传递的A实例调用foo,如下所示:

 void bar() throws Exception { Stream<A> as = ... as.forEach(a -> a.foo()); } 

问题:如何正确处理exception? 该代码不会在我的机器上编译,因为我没有处理可能由foo()引发的exception。 throws Exception bar在这里似乎没用。 这是为什么?

您需要将您的方法调用包装到另一个方法中,而不要抛出已检查的exception 。 您仍然可以抛出任何RuntimeException的子类。

一个正常的包装习惯是这样的:

 private void safeFoo(final A a) { try { a.foo(); } catch (Exception ex) { throw new RuntimeException(ex); } } 

(超typesexception仅用作示例,请勿自己尝试捕捉它)

然后你可以调用它: as.forEach(this::safeFoo)

这个问题可能有点老了,但是因为我认为这里的“正确”答案只是一个方法,可能会在代码中稍后导致一些问题隐藏问题。 即使有一点争议 ,检查exception也是有原因的。

在我看来,最优雅的方式是你可以findMisha在这里只通过执行“期货”中的操作在Java 8stream中聚合运行时exception 。 所以你可以运行所有的工作部分,并收集不工作的例外作为一个单一的。 否则,您可以将它们全部收集到列表中,并在稍后处理。

类似的方法来自Benji Weber 。 他build议创build一个自己的types来收集工作而不是工作部分。

根据您真正想要实现的input值和输出值之间的简单映射,发生的exception也可能适用于您。

如果您不喜欢这些方式中的任何一种,请考虑使用(取决于原始exception)至less有一个自己的exception。

如果你想要调用foo ,并且你喜欢传播exception(没有包装),你也可以直接使用Java的for循环(在把Stream变成一个有一定欺骗的Iterable之后):

 for (A a : (Iterable<A>) as::iterator) { a.foo(); } 

至less,这是我在JUnittesting中所做的,我不想经历包装我检查过的exception的麻烦(实际上我更倾向于使用我的testing来扔掉未包装的原始exception)

我build议使用谷歌Guava Throwables类

传播Throwable throwable)

如果它是RuntimeException或Error的实例,则按原样传播,或者作为最后的手段,将其包装在RuntimeException中,然后传播。

 void bar() { Stream<A> as = ... as.forEach(a -> { try { a.foo() } catch(Exception e) { throw Throwables.propagate(e); } }); } 

你可以用这种方式打包和解包exception。

 class A { void foo() throws Exception { throw new Exception(); } }; interface Task { void run() throws Exception; } static class TaskException extends RuntimeException { private static final long serialVersionUID = 1L; public TaskException(Exception e) { super(e); } } void bar() throws Exception { Stream<A> as = Stream.generate(()->new A()); try { as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo() } catch (TaskException e) { throw (Exception)e.getCause(); } } static void wrapException(Task task) { try { task.run(); } catch (Exception e) { throw new TaskException(e); } } 

您可能想要执行以下任一操作:

  • 传播检查exception,
  • 包装它并传播未经检查的exception,或
  • 捕捉exception并停止传播。

几个库让你轻松做到这一点。 下面的例子是用我的NoException库编写的。

 // Propagate checked exception as.forEach(Exceptions.sneak().consumer(A::foo)); // Wrap and propagate unchecked exception as.forEach(Exceptions.wrap().consumer(A::foo)); as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo)); // Catch the exception and stop propagation (using logging handler for example) as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo)));