简体   繁体   English

如何在java 8流上使用foreach循环进行迭代

[英]How to iterate with foreach loop over java 8 stream

Suppose we try to apply to java 8 stream a lambda that could throw checked exception:假设我们尝试将一个可能引发检查异常的 lambda 应用到 java 8 流:

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

This won't compile.这不会编译。

One workaround is to nest checked exception in RuntimeException but it complicates later exception handling and it's just ugly:一种解决方法是在RuntimeException中嵌套检查的异常,但这会使以后的异常处理复杂化,而且很难看:

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

Alternative workaround could be to convert limited functional forEach to plain old foreach loop that is more friendly to checked exceptions.替代解决方法可能是将有限的功能forEach转换为对检查异常更友好的普通旧 foreach 循环

But naive approaches fail:但是天真的方法失败了:

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

Update更新

A trick that answers this question was previosly posted at Why does Stream<T> not implement Iterable<T>?回答这个问题的技巧之前发布在为什么 Stream<T> 不实现 Iterable<T>? as side answer that doesn't really answer that question itself.作为侧面答案,它本身并不能真正回答这个问题。 I think this is not enough to qualify this question as duplicate of that one because they ask different things.我认为这不足以使这个问题成为那个问题的重复,因为他们提出了不同的问题。

By definition foreach loop requires an Iterable to be passed in. 根据定义,foreach 循环需要传入一个Iterable

It can be achieved with anonymous class:它可以通过匿名类来实现:

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

This can be simplified with lambda because Iterable is a functional interface :这可以用lambda简化,因为Iterable是一个函数式接口

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

This can be converted to method reference :这可以转换为方法参考

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

Explicit cast can be avoided with intermediate variable or method param:使用中间变量或方法参数可以避免显式转换:

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

There is also StreamEx library in maven central that features iterable streams and other perks out of the box. maven Central 中还有StreamEx库,它具有可迭代的流和其他开箱即用的特性。


Here are some most popular questions and approaches that provide workarounds on checked exception handling within lambdas and streams:以下是一些最流行的问题和方法,它们提供了在 lambda 和流中检查异常处理的变通方法:

Java 8 Lambda function that throws exception? 抛出异常的Java 8 Lambda函数?

Java 8: Lambda-Streams, Filter by Method with Exception Java 8:Lambda-Streams,按异常方法过滤

How can I throw CHECKED exceptions from inside Java 8 streams? 如何从 Java 8 流中抛出 CHECKED 异常?

Java 8: Mandatory checked exceptions handling in lambda expressions. Java 8:在 lambda 表达式中强制检查异常处理。 Why mandatory, not optional? 为什么是强制性的,而不是可选的?

jOOλ Unchecked jOOλ 未选中

Lombok @SneakyThrows龙目岛@SneakyThrows

Kotlin ;)科特林;)

Stream does not implement Iterable, nor is it an array, so it is not eligible for use in an enhanced for loop. Stream 没有实现 Iterable,也不是数组,因此它不适合在增强的 for 循环中使用。 The reason it does not implement Iterable is because it is a single use data structure.它没有实现 Iterable 的原因是因为它是一个单一用途的数据结构。 Each time Iterable.iterator is called, a new Iterator should be returned which covers all of the elements.每次调用 Iterable.iterator 时,都应该返回一个覆盖所有元素的新 Iterator。 The iterator method on Stream just reflects the current state of the Stream. Stream 上的迭代器方法只是反映了 Stream 的当前状态。 It is effectively a different view of the Stream.它实际上是 Stream 的不同视图。

You could make a class which implements Iterable by wrapping a stream for use in the enhanced for loop.您可以通过包装流以在增强的 for 循环中使用来创建一个实现 Iterable 的类。 But this is a questionable idea as you cannot truly implement Iterable (as described above).但这是一个值得怀疑的想法,因为您无法真正实现 Iterable(如上所述)。

I wrote an extension to the Stream API which allows for checked exceptions to be thrown.我为 Stream API编写了一个扩展,它允许抛出检查的异常。

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

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

You can also do it like this:你也可以这样做:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM