Java 8:如何使用流中的异常抛出方法?

问题

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

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

现在我想为一个流如下所示的每个实例调用foo:A

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

问题:如何正确处理异常?代码无法在我的机器上编译,因为我没有处理foo()可能抛出的异常。 throws Exception of bar似乎在这里毫无用处。这是为什么?


#1 热门回答(96 赞)

你需要将方法调用包装到另一个方法调用中,而不会抛出检查异常。你仍然可以抛出RuntimeException的子类。

一个普通的包装成语是这样的:

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

(超类型例外Exception被用作例子,从不试图自己抓住它)

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


#2 热门回答(21 赞)

如果你想要的只是调用foo,并且你更喜欢按原样传播异常(不包装),你也可以使用Java的forloop(在将Stream转换为带有sometrickery的Iterable之后):

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

至少,这是我在JUnit测试中所做的,在那里我不想经历包装我的已检查异常的麻烦(实际上更喜欢我的测试来抛出未包装的原始异常)


#3 热门回答(13 赞)

这个问题可能有点旧,但因为我认为这里的"正确"答案只是一种可能导致某些问题隐藏在代码后面的问题。即使有一点Controversy,也存在Checked Exceptions。

你认为最优雅的方式是Misha这里给出的368585757只是在"期货"中执行动作。因此,你可以运行所有工作部件并收集不工作的例外作为单个部件。否则,你可以在列表中收集它们并稍后处理它们。

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

根据你真正想要实现的目标,输入值和输出值之间的简单映射可能也会对你有所帮助。

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