Java 8:如何使用流中的异常抛出方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23548589/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8: How do I work with exception throwing methods in streams?
提问by Bastian
Suppose I have a class and a method
假设我有一个类和一个方法
class A {
void foo() throws Exception() {
...
}
}
Now I would like to call foo for each instance of A
delivered by a stream like:
现在我想为每个A
由流传递的实例调用 foo ,例如:
void bar() throws Exception {
Stream<A> as = ...
as.forEach(a -> a.foo());
}
Question: How do I properly handle the exception? The code does not compile on my machine because I do not handle the possible exceptions that can be thrown by foo(). The throws Exception
of bar
seems to be useless here. Why is that?
问题:如何正确处理异常?代码无法在我的机器上编译,因为我没有处理 foo() 可能抛出的异常。在throws Exception
的bar
似乎是没用在这里。这是为什么?
采纳答案by skiwi
You need to wrap your method call into another one, where you do not throw checked exceptions. You can still throw anything that is a subclass of RuntimeException
.
您需要将您的方法调用包装到另一个方法中,您不会在其中抛出已检查的异常。您仍然可以抛出任何属于RuntimeException
.
A normal wrapping idiom is something like:
一个普通的包装成语是这样的:
private void safeFoo(final A a) {
try {
a.foo();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
(Supertype exception Exception
is onlyused as example, never try to catch it yourself)
(超类型的例外Exception
是仅作为例子,切勿尝试自行抓住它)
Then you can call it with: as.forEach(this::safeFoo)
.
然后你可以用: 调用它as.forEach(this::safeFoo)
。
回答by aalku
You can wrap and unwrap exceptions this way.
您可以通过这种方式包装和解开异常。
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);
}
}
回答by avandeursen
If all you want is to invoke foo
, and you prefer to propagate the exception as is (without wrapping), you can also just use Java's for
loop instead (after turning the Stream into an Iterable with some trickery):
如果您只想调用foo
,并且更喜欢按原样传播异常(不包装),您也可以只使用 Java 的for
循环(在使用一些技巧将 Stream 转换为 Iterable 之后):
for (A a : (Iterable<A>) as::iterator) {
a.foo();
}
This is, at least, what I do in my JUnit tests, where I don't want to go through the trouble of wrapping my checked exceptions (and in fact prefer my tests to throw the unwrapped original ones)
这至少是我在 JUnit 测试中所做的,在那里我不想经历包装已检查异常的麻烦(实际上更喜欢我的测试抛出未包装的原始异常)
回答by Mariano
This question may be a little old, but because I think the "right" answer here is only one way which can lead to some issues hidden Issues later in your code. Even if there is a little Controversy, Checked Exceptions exist for a reason.
这个问题可能有点老,但因为我认为这里的“正确”答案只是一种方法,它可能会导致代码后面隐藏的一些问题。即使有一点争议,Checked Exceptions 的存在也是有原因的。
The most elegant way in my opinion can you find was given by Misha here Aggregate runtime exceptions in Java 8 streamsby just performing the actions in "futures". So you can run all the working parts and collect not working Exceptions as a single one. Otherwise you could collect them all in a List and process them later.
在我看来,你能找到的最优雅的方式是 Misha 在这里 通过只执行“futures”中的操作来 聚合 Java 8 流中的运行时异常。因此,您可以运行所有工作部件并将不工作的异常作为一个单独的异常收集。否则,您可以将它们全部收集在一个列表中并稍后处理它们。
A similar approach comes from Benji Weber. He suggests to create an own type to collect working and not working parts.
Benji Weber提出了类似的方法。他建议创建一个自己的类型来收集工作部件而不是工作部件。
Depending on what you really want to achieve a simple mapping between the input values and Output Values occurred Exceptions may also work for you.
根据您真正想要实现的输入值和发生的输出值之间的简单映射,异常也可能对您有用。
If you don't like any of these ways consider using (depending on the Original Exception) at least an own exception.
如果您不喜欢这些方法中的任何一种,请考虑使用(取决于原始异常)至少一个自己的异常。
回答by yanefedor
I suggest to use Google Guava Throwables class
我建议使用 Google Guava Throwables 类
propagate(Throwablethrowable)
Propagates throwable as-is if it is an instance of RuntimeException or Error, or else as a last resort, wraps it in a RuntimeException and then propagates.**
传播(Throwablethrowable )
如果它是 RuntimeException 或 Error 的实例,则按原样传播 throwable,否则作为最后的手段,将其包装在 RuntimeException 中然后传播。**
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
throw Throwables.propagate(e);
}
});
}
UPDATE:
更新:
Now that it is deprecated use:
现在它已被弃用:
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
});
}
回答by Robert Va?an
You might want to do one of the following:
您可能想要执行以下操作之一:
- propagate checked exception,
- wrap it and propagate unchecked exception, or
- catch the exception and stop propagation.
- 传播检查异常,
- 包装它并传播未经检查的异常,或
- 捕获异常并停止传播。
Several librarieslet you do that easily. Example below is written using my NoExceptionlibrary.
有几个库可以让您轻松地做到这一点。下面的示例是使用我的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)));
回答by Kashyap
More readable way:
更易读的方式:
class A {
void foo() throws MyException() {
...
}
}
Just hide it in a RuntimeException
to get it past forEach()
只需将其隐藏在 a 中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();
}
}
Although at this point I won't hold against someone if they say skip the streams and go with a for loop, unless:
尽管此时我不会反对某人说跳过流并使用 for 循环,除非:
- you're not creating your stream using
Collection.stream()
, i.e. not straight forward translation to a for loop. - you're trying to use
parallelstream()
- 您不是使用 来创建流
Collection.stream()
,即不是直接转换为 for 循环。 - 你正在尝试使用
parallelstream()