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

2022-09-01 14:08:00

假设我们尝试将一个可能引发已检查异常的 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

这不会编译。

一种解决方法是将已检查的异常嵌套在其中,但它会使以后的异常处理复杂化,而且它非常丑陋:RuntimeException

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

替代解决方法是将有限的功能转换为普通的旧 foreach 循环,这对检查的异常更友好。forEach

但幼稚的方法失败了:

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

更新

回答这个问题的一个技巧之前被张贴在为什么Stream<T>不实现Iterable<T>?作为侧面答案,并没有真正回答这个问题本身。我认为这不足以使这个问题成为那个问题的重复,因为他们问了不同的事情。


答案 1

根据定义,foreach 循环需要传入一个可迭代对象。

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

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

这可以通过lambda进行简化,因为它是一个功能接口Iterable

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

这可以转换为方法参考

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

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

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

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


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

Java 8 Lambda 函数会引发异常吗?

Java 8:Lambda 流,按方法筛选,但有异常

如何从 Java 8 流中抛出 CHECKED 异常?

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

jOOλ Unchecked

龙目岛@SneakyThrows

科特林 ;)


答案 2

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

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