Java8:如何处理流中的异常抛出方法?
假设我有一个类和一个方法Java8:如何处理流中的异常抛出方法?,java,java-8,unhandled-exception,java-stream,Java,Java 8,Unhandled Exception,Java Stream,假设我有一个类和一个方法 class A { void foo() throws Exception() { ... } } 现在,我想为以下流提供的A的每个实例调用foo: void bar() throws Exception { Stream<A> as = ... as.forEach(a -> a.foo()); } void bar()引发异常{ 流作为=。。。 as.forEach(a->a.foo()); } 问题:如何正确处理异常
class A {
void foo() throws Exception() {
...
}
}
现在,我想为以下流提供的A
的每个实例调用foo:
void bar() throws Exception {
Stream<A> as = ...
as.forEach(a -> a.foo());
}
void bar()引发异常{
流作为=。。。
as.forEach(a->a.foo());
}
问题:如何正确处理异常?代码没有在我的机器上编译,因为我没有处理foo()可能引发的异常。
条的抛出异常
,在这里似乎没有用。为什么会这样?您需要将您的方法调用包装到另一个方法调用中,这样您就不会抛出选中的异常。您仍然可以抛出属于RuntimeException
子类的任何内容
正常的包装习惯用法类似于:
private void safeFoo(final A a) {
try {
a.foo();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
(超类型异常<代码>异常代码>仅用作示例,切勿尝试自己捕获)
然后您可以使用以下命令调用它:as.forEach(this::safeFoo)
您可以这样包装和展开异常
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);
}
}
A类{
void foo()引发异常{
抛出新异常();
}
};
接口任务{
void run()抛出异常;
}
静态类TaskException扩展了RuntimeException{
私有静态最终长serialVersionUID=1L;
公共任务异常(异常e){
超级(e);
}
}
void bar()引发异常{
Stream as=Stream.generate(()->new A());
试一试{
as.forEach(a->wrapException(()->a.foo());//或a::foo代替()->a.foo()
}捕获(任务异常e){
抛出(异常)e.getCause();
}
}
静态无效包装异常(任务){
试一试{
task.run();
}捕获(例外e){
抛出新任务异常(e);
}
}
如果您只想调用foo
,并且您更喜欢按原样传播异常(无需包装),那么您也可以使用Java的for
循环(在将流转换为可与某些对象绑定的Iterable之后):
(A:(Iterable)as::iterator)的{
a、 foo();
}
这至少是我在JUnit测试中所做的,我不想麻烦地包装我的已检查异常(事实上,我更喜欢我的测试抛出未包装的原始异常)这个问题可能有点老,但因为我认为“正确”这里的答案是唯一一种可能导致一些问题的方法,这些问题会隐藏在代码的后面。即使有一点,检查异常的存在也是有原因的
在我看来,你能找到的最优雅的方式是米沙在这里给出的
通过执行“未来”中的操作。因此,您可以运行所有工作部件,并将非工作异常收集为单个异常。否则,您可以将它们全部收集到一个列表中,稍后再进行处理
类似的方法也来自美国。他建议创建一个自己的类型来收集工作部件和非工作部件
根据您真正想要实现的输入值和输出值之间的简单映射,异常可能也适用于您
如果你不喜欢任何一种方法,考虑使用(取决于最初的例外)至少有一个自己的例外。
< P>我建议使用谷歌番石榴掷物类< /P>
传播(可丢弃可丢弃)
传播可丢弃的内容,就像它是一个
RuntimeException或Error的实例,或者作为最后手段,包装
它在运行时异常中运行,然后传播**
void bar(){
流作为=。。。
as.forEach(a->{
试一试{
a、 foo()
}捕获(例外e){
抛掷物。传播(e);
}
});
}
更新:
现在它已被弃用,请使用:
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
});
}
void bar(){
流作为=。。。
as.forEach(a->{
试一试{
a、 foo()
}捕获(例外e){
throwIfUnchecked(e);
抛出新的运行时异常(e);
}
});
}
您可能需要执行以下操作之一:
- 传播选中的异常
- 包装它并传播未经检查的异常,或
- 捕获异常并停止传播
让你轻松地做到这一点。下面的示例是使用我的库编写的
更具可读性的方式:
class A {
void foo() throws MyException() {
...
}
}
只需将其隐藏在运行时异常中
即可使其通过forEach()
void bar()引发MyException{
流作为=。。。
试一试{
as.forEach(a->{
试一试{
a、 foo();
}捕获(MyException e){
抛出新的运行时异常(e);
}
});
}捕获(运行时异常e){
抛出(MyException)e.getCause();
}
}
尽管在这一点上,如果有人说跳过流并使用for循环,我不会反对,除非:
- 您没有使用
Collection.stream()
创建流,也就是说,没有直接转换到for循环
- 您正在尝试使用
parallelstream()
如果希望它是一个包装器方法,我会将其声明为静态。它没有使用“this”中的任何内容。遗憾的是,我们必须这样做,而不是使用本机异常。。。。噢,Java,它先给后取away@Stephan这个答案被删除了,但它仍然可以在这里找到:这将使我的公司的代码审查立即失败:我们不允许抛出未经检查的异常。@Steliosadamantids说,这条规则限制性极强,而且适得其反。您是否知道,所有api中的所有方法都有权抛出所有类型的运行时异常,而您甚至不必知道(当然知道)?您是否因为没有实现检查异常的概念而禁止javascript?如果我是您的首席开发人员,我会取而代之的是禁止检查异常。相关:Use的可能重复。这应该标记为正确答案。+。但我不能说这是一个好帖子。你应该详细阐述一下。自己的异常有什么帮助?W
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
});
}
// 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)));
class A {
void foo() throws MyException() {
...
}
}
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();
}
}