假设我有一个类和一个方法
class A {
void foo() throws Exception() {
...
}
}
现在我想为像A
的每个实例调用foo,如:
void bar() throws Exception {
Stream<A> as = ...
as.forEach(a -> a.foo());
}
问题:如何正确处理异常?代码无法在我的机器上编译,因为我没有处理foo()可能抛出的异常。 throws Exception
的{{1}}似乎在这里毫无用处。那是为什么?
答案 0 :(得分:124)
您需要将方法调用包装到另一个方法中,不要抛出已检查的异常。你仍然可以抛出任何RuntimeException
的子类。
正常的包装习惯用语如下:
private void safeFoo(final A a) {
try {
a.foo();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
(超类型异常Exception
仅 用作示例,永远不要试图自己抓住它)
然后你可以用as.forEach(this::safeFoo)
来调用它。
答案 1 :(得分:13)
这个问题可能有点旧,但因为我认为&#34;对&#34;这里的答案只有一种方法可以导致一些问题隐藏在代码中的问题。即使有一点Controversy,也存在Checked Exceptions。
我认为最优雅的方式是Misha在Aggregate runtime exceptions in Java 8 streams给出的 只需执行&#34;期货&#34;中的操作。因此,您可以运行所有工作部件,并将单独的异常工作收集起来。否则,您可以在列表中收集它们并稍后处理它们。
类似的方法来自Benji Weber。他建议创建一个自己的类型来收集工作而不是工作部分。
根据您真正想要实现的目标,输入值和输出值之间的简单映射可能也适用于例外情况。
如果您不喜欢这些方式中的任何一种,请考虑使用(取决于原始例外)至少一个自己的例外。
答案 2 :(得分:9)
我建议使用Google 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);
}
});
}
更新:
现在不推荐使用:
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
});
}
答案 3 :(得分:7)
您可以通过这种方式包装和解包异常。
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);
}
}
答案 4 :(得分:7)
您可能希望执行以下操作之一:
Several libraries可让您轻松完成。以下示例使用我的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)));
答案 5 :(得分:1)
更易读的方式:
class A {
void foo() throws MyException() {
...
}
}
只需将其隐藏在RuntimeException
中,即可将其隐藏forEach()
void bar() throws MyException {
Stream<A> as = ...
try {
as.forEach(a -> {
try {
a.foo();
} catch(MyException e) {
throw new RuntimeException(e);
}
});
} catch(RuntimeException e) {
throw (MyException) e.getCause();
}
}
虽然在这一点上,如果他们说跳过溪流并使用for循环,我就不会反对某人,除非:
Collection.stream()
创建自己的流,即不能直接转换为for循环。parallelstream()