2014-11-01 85 views
4

我最近了解到Stream S IN的Java 8,看到这个例子:了解Java 8流的过滤方法

IntStream stream = IntStream.range(1, 20); 

现在,让我们说,我们想通过3和5,找到第一个号码,不要divisable两我们很可能filter两次findFirst如下:

OptionalInt result = stream.filter(x -> x % 3 == 0) 
           .filter(x -> x % 5 == 0) 
           .findFirst(); 

这一切听起来很合理。令人惊讶的部分来了,当我试图做到这一点:

OptionalInt result = stream.filter(x -> {System.out.println(x); return x % 3 == 0;}) 
          .filter(x -> {System.out.println(x); return x % 5 == 0;}) 
          .findFirst(); 

System.out.println(result.getAsInt()); 

我希望得到的东西,如:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20然后:3 6 9 12 15 18。因为我们首先遍历1之间所有的号码20,过滤出那些divisable 3,然后重复这个新Stream,发现那些通过5

是divisable而是我得到这个输出:1 2 3 3 4 5 6 6 7 8 9 9 10 11 12 12 13 14 15 15 15

它看起来好像并没有覆盖所有的数字。此外,它看起来像检查x % 5 == 0只能为可被3整除的那些数字。

我不明白它是如何来不遍布所有的数字。

下面的代码的在线片段:http://www.tryjava8.com/app/snippets/5454a7f2e4b070922a64002b

回答

7

好了,了解有关信息流的事情是,不像名单,他们不(一定)持有的所有物品,而是在同一时间计算每个项目(懒惰评估)。

这意味着当你做了IntStream stream = IntStream.range(1, 20);你实际上没有创建一个包含20个项目的集合。您创建了一个动态计算的集合。每次调用此流的next将计算下一个项目。其余的项目仍然“不存在”(有点说话)。

同样适用于过滤器。

当您添加检查除法3的过滤器时,您将得到一个由2个计算组成的新流 - 第一个返回数字从1到20,第二个计算返回分割的数字通过3.重要的是要明白,每次只计算第一项。这就是为什么当您将除法检查添加5时,它只能处理那些可以被3整除的项目。同样也是为什么打印停止在15处。findFirst方法返回第一个通过所有3个计算的数字(1- 20个量程计算,3个计算除以5个计算除法)。

3

流是一种用于高效处理集合的惰性评估机制。这意味着除非最终(终端)操作需要,否则不评估流上的所有中间操作。

在您的示例中,终端操作是firstFirst()。这意味着Stream将评估中间操作的流水线,直到它发现通过将输入流传递通过所有中间操作而产生的单个int为止。

第二个过滤器只接收通过第一个过滤器的整数,所以它只处理数字3,6,9,12,15,然后停止,因为15通过了过滤器,并且提供了findFirst()操作的唯一输出需要。

只要终端操作仍然需要数据,第一个过滤器将只处理输入流的整数,因此它将只处理1到15.