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

时间:2015-07-29 14:11:10

标签: java for-loop foreach java-8 java-stream

假设我们尝试向java 8流应用一个可能抛出已检查异常的lambda:

Stream<String> stream = Stream.of("1", "2", "3");
Writer writer = new FileWriter("example.txt");

stream.forEach(s -> writer.append(s)); // Unhandled exception: java.io.IOException

这不会编译。

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

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

替代解决方法可能是将limited功能forEach转换为plain old foreach loop,这对检查异常更友好。

但天真的方法失败了:

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

for (String s : stream.iterator()) { // foreach not applicable to type 'java.util.Iterator<java.lang.String>'
    writer.append(s);
}

更新

回答这个问题的一个技巧在Why does Stream<T> not implement Iterable<T>?side answer为主,并没有真正回答这个问题本身。 我认为这不足以将这个问题视为该问题的重复,因为他们会提出不同的问题。

4 个答案:

答案 0 :(得分:28)

By definition foreach循环需要传入Iterable

可以使用匿名类来实现:

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

这可以通过lambda进行简化,因为Iterablefunctional interface

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

这可以转换为method reference

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

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

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

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

以下是一些最受欢迎的问题和方法,它们提供了lambda和流中已检查异常处理的变通方法:

Java 8 Lambda function that throws exception?

Java 8: Lambda-Streams, Filter by Method with Exception

How can I throw CHECKED exceptions from inside Java 8 streams? (Not wrapping it into unchecked exceptions)

Java 8: Mandatory checked exceptions handling in lambda expressions. Why mandatory, not optional?

jOOλ Unchecked

Kotlin;)

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

I wrote an extension到Stream API,允许抛出已检查的异常。

Stream<String> stream = Stream.of("1", "2", "3");
Writer writer = new FileWriter("example.txt");

ThrowingStream.of(stream, IOException.class).forEach(writer::append);

答案 3 :(得分:1)

你也可以这样做:

Path inputPath = Paths.get("...");
Stream<Path> stream = Files.list(inputPath);

for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); )
{
    Path path = iterator.next();
    // ...
}
相关问题