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