Java 8:如何使用流中的异常抛出方法?

Bas*_*ian 154 java unhandled-exception java-8 java-stream

假设我有一个类和一个方法

class A {
  void foo() throws Exception() {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我想为A一个流传递的每个实例调用foo,如:

void bar() throws Exception {
  Stream<A> as = ...
  as.forEach(a -> a.foo());
}
Run Code Online (Sandbox Code Playgroud)

问题:如何正确处理异常?代码无法在我的机器上编译,因为我没有处理foo()可能抛出的异常.在throws Exceptionbar似乎是没用在这里.这是为什么?

ski*_*iwi 134

您需要将方法调用包装到另一个方法中,在此方法中不会抛出已检查的异常.你仍然可以抛出任何子类RuntimeException.

一个普通的包装习语是这样的:

private void safeFoo(final A a) {
    try {
        a.foo();
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}
Run Code Online (Sandbox Code Playgroud)

(超类型的例外Exception作为例子,切勿尝试自行抓住它)

然后你可以用:as.forEach(this::safeFoo).

  • 令人遗憾的是我们必须这样做而不是使用我们的原生例外....哦,Java,它给出然后带走 (191认同)
  • @SteliosAdamantidis该规则的限制极其严格,适得其反。您是否知道所有api中的所有方法都被授权抛出所有类型的运行时异常,而您甚至不必知道(当然是)?您是否因为未实现检查异常的概念而禁止javascript?如果我是您的首席开发人员,那么我将禁止检查异常。 (6认同)
  • 这将立即导致我公司的代码审查失败:我们不允许抛出未经检查的异常. (3认同)

ava*_*sen 27

如果您只想调用foo,并且您希望按原样传播异常(不包装),那么您也可以使用Java for循环(在将Stream转换为具有一些技巧的Iterable之后):

for (A a : (Iterable<A>) as::iterator) {
   a.foo();
}
Run Code Online (Sandbox Code Playgroud)

至少,这是我在JUnit测试中所做的,我不想经历包装我检查的异常的麻烦(实际上更喜欢我的测试抛弃未包装的原始异常)


Mar*_*ano 13

这个问题可能有点老了,但因为我认为"正确"的答案在这里只有一条路可导致隐藏的问题后面的代码中的一些问题.即使存在一些争议,也存在Checked Exceptions.

在我看来,最优雅的方式可你发现在这里给出的米沙 在Java中8流聚集运行时异常 由刚刚在"期货"执行的操作.因此,您可以运行所有工作部件,并将单独的异常工作收集起来.否则,您可以在列表中收集它们并稍后处理它们.

类似的方法来自Benji Weber.他建议创建一个自己的类型来收集工作而不是工作部分.

根据您真正想要实现的目标,输入值和输出值之间的简单映射可能也会对您有所帮助.

如果您不喜欢这些方法中的任何一种,请考虑使用(取决于原始异常)至少一个自己的异常.

  • 这应该标记为正确答案.+.但我不能说这是一个好帖子.你应该大大详细说明.自己的例外如何帮助?发生了什么异常?你为什么不在这里带来不同的变种?在SO中,将所有示例代码都放在引用中被认为是一种偶然禁止的帖子风格.您的文字看起来像一堆评论. (3认同)
  • 您应该能够选择要捕获它们的级别,然后流将其弄乱。Stream API应该允许您携带异常,直到最后一个操作(如collect)为止,然后在该处使用处理程序进行处理,否则将引发异常。stream.map(Streams.passException(x-&gt; mightThrowException(x)))。catch(e-&gt; whatToDo(e))。collect(...)它期望例外,并允许您像期货一样处理它们。 (2认同)

fbo*_*kov 10

我建议使用Google Guava Throwables类

传播( Throwable throwable)

如果它是RuntimeException或Error的实例,则传播throwable as as,否则作为最后的手段,将其包装在RuntimeException中然后传播.**

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            throw Throwables.propagate(e);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

更新:

现在不推荐使用:

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 这个方法[弃用](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)(不幸的是). (4认同)

aal*_*lku 8

您可以通过这种方式包装和解包异常.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Rob*_*žan 8

您可能希望执行以下操作之一:

  • 传播检查异常,
  • 将其包装并传播未经检查的异常,或
  • 捕捉异常并停止传播.

有几个库可以让您轻松完成.下面的示例是使用我的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)));
Run Code Online (Sandbox Code Playgroud)

  • 图书馆干得好!我正想写一些类似的东西。 (3认同)

Kas*_*yap 6

更易读的方式:

class A {
  void foo() throws MyException() {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

只需将其隐藏在 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();
      }
  }
Run Code Online (Sandbox Code Playgroud)

尽管在这一点上,如果有人说跳过流并使用 for 循环,我不会反对他们,除非:

  • 您没有使用创建流Collection.stream(),即不是直接转换为 for 循环。
  • 你正在尝试使用parallelstream()