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