如何使用foreach循环遍历java 8流

假设我们尝试将一个可能抛出已检查exception的lambda应用于java 8流:

Stream stream = Stream.of("1", "2", "3"); Writer writer = new FileWriter("example.txt"); stream.forEach(s -> writer.append(s)); // Unhandled exception: java.io.IOException 

这不会编译。

一种解决方法是在RuntimeException嵌套已检查的exception,但它使以后的exception处理变得复杂,而且它只是丑陋:

 stream.forEach(s -> { try { writer.append(s); } catch (IOException e) { throw new RuntimeException(e); } }); 

替代解决方法可能是将有限的function性forEach转换为对检查exception更友好的普通旧foreach 循环 。

但天真的方法失败了:

 for (String s : stream) { // for-each not applicable to expression type 'java.util.stream.Stream' writer.append(s); } for (String s : stream.iterator()) { // foreach not applicable to type 'java.util.Iterator' writer.append(s); } 

更新

回答这个问题的一个技巧主要发布在为什么Stream 没有实现Iterable ? 作为副答案 ,并没有真正回答这个问题本身。 我认为这不足以将这个问题视为该问题的重复,因为他们会提出不同的问题。

根据定义, foreach循环需要传入Iterable 。

它可以通过匿名类来实现:

  for (String s : new Iterable() { @Override public Iterator iterator() { return stream.iterator(); } }) { writer.append(s); } 

这可以通过lambda简化,因为Iterable是一个function接口 :

  for (String s : (Iterable) () -> stream.iterator()) { writer.append(s); } 

这可以转换为方法参考 :

  for (String s : (Iterable) stream::iterator) { writer.append(s); } 

使用中间变量或方法参数可以避免显式强制转换:

  Iterable iterable = stream::iterator; for (String s : iterable) { writer.append(s); } 

在maven中心还有一个StreamEx库,它具有可迭代流和开箱即用的其他特权。


以下是一些最流行的问题和方法,它们提供了lambdas和流中已检查exception处理的变通方法:

抛出exception的Java 8 Lambda函数?

Java 8:Lambda-Streams,按方法过滤,具有exception

如何从Java 8流中抛出CHECKEDexception? (不将其包装到未经检查的例外中)

Java 8:在lambda表达式中强制检查exception处理。 为什么强制,不是可选的?

jOOλ未选中

科特林 ;)

Stream不实现Iterable,也不是数组,因此它不适用于增强的for循环。 它没有实现Iterable的原因是因为它是一个单独使用的数据结构。 每次调用Iterable.iterator时,都应返回一个覆盖所有元素的新迭代器。 Stream上的迭代器方法只反映了Stream的当前状态。 它实际上是Stream的不同视图。

您可以通过包装流以在增强的for循环中使用来创建实现Iterable的类。 但这是一个值得怀疑的想法,因为你无法真正实现Iterable(如上所述)。

我写了一个 Stream API 的扩展 ,它允许抛出已检查的exception。

 Stream stream = Stream.of("1", "2", "3"); Writer writer = new FileWriter("example.txt"); ThrowingStream.of(stream, IOException.class).forEach(writer::append); 

你也可以这样做:

 Path inputPath = Paths.get("..."); Stream stream = Files.list(inputPath); for (Iterator iterator = stream.iterator(); iterator.hasNext(); ) { Path path = iterator.next(); // ... }