Lambda 无限流与滤波器

Lambda 无限流与滤波器,lambda,java-8,java-stream,Lambda,Java 8,Java Stream,我不熟悉Java 8流API,实际上我不明白为什么我的代码不能工作: import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamExample { public static void main(String[] args) { List<Integer> numbers = Stream.iter

我不熟悉Java 8流API,实际上我不明白为什么我的代码不能工作:

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Stream.iterate(0, x -> x+3)
                                        .filter(x -> x>10 && x<100).peek(System.out::println)
                                        .collect(Collectors.toList());
        numbers.forEach(System.out::println);
    }
}
import java.util.List;
导入java.util.stream.collector;
导入java.util.stream.stream;
公共类流示例{
公共静态void main(字符串[]args){
列表编号=流。迭代(0,x->x+3)

.filter(x->x>10&&x编译器和运行时都不知道
filter
将过滤掉100以外的所有数字。因此,运行时继续生成无限整数并对其应用过滤器

有多种方法可以解决此问题:

使用
limit
将无限流截断为有限流。这使得下面的过滤器有点不必要(如果设置了严格的限制,则只有x>10测试仍然相关)

一般来说,流的“惰性”意味着它们只有在遇到终端(final)操作时才开始执行。如果操作需要处理列表中的所有元素(例如
toList
does),则不应将无限流传递给它


处理无限流时,您可以选择将其截断为有限流(使用limit)或使用不必处理流的所有元素的终端操作(例如:anyMatch、findFirst、findAny)。

事实上,我不明白为什么filter()中的数字不满足条件就我所知,Java中的流是惰性的,所以应该只生成满足条件的数字。使用limit()没有意义,因为我已经计算出了10到100之间(或其他范围)的数字除以3的数量因此,使用流没有任何意义,因为我必须在实际创建集合之前知道集合。您的第二个解决方案也存在同样的问题-因为当我将范围从1更改为98765时,我不想计算它们之间有多少个数字除以3-最好使用范围(10100)。过滤器(x->x%3==0)顺便说一句,我的问题是关于为什么在我的例子中Java流的惰性不起作用的一般性问题。@marekx99您可以使用更高的限制,比如说100,在这种情况下,您仍然需要过滤器(因为您知道过滤器传递的数字不会超过99)。流是惰性的这一事实意味着它们只有在遇到最后一个操作时才开始执行。如果操作是
toList
,则您请求将通过过滤器的所有整数放入列表中,为了知道哪些整数通过过滤器,Java必须对流中的每个整数应用过滤器(这是一个问题,因为它们的数量是无限的)。@marekx99我希望我的评论能够澄清为什么它不能以这种方式工作。当你处理一个无限流时,你的选择是要么将它截断为一个有限流(使用limit),要么使用一个终端操作,不必处理流的所有元素(示例:anyMatch,findFirst,findAny)。@marekx99:还有您尚未提及的第二个疏忽:
int
值范围是有限的,即使您的流不是有限的。
int
值在您不限制流时会溢出。因此您可以使用
IntStream.range(0,Integer.MAX_value)
解决您的所有问题(如果hotspot optimizer足够智能,那么它不一定是一个大的性能问题)…
public static void main(String[] args) {
    List<Integer> numbers = Stream.iterate(0, x -> x+3)
                                    .limit(34)
                                    .filter(x -> x>10 && x<100).peek(System.out::println)
                                    .collect(Collectors.toList());
    numbers.forEach(System.out::println);
}
public static void main(String[] args) {
    List<Integer> numbers = IntStream.range(0, 34)
                                    .map(x -> 3*x)
                                    .collect(Collectors.toList());
    numbers.forEach(System.out::println);
}