什么是Stream (Advanced)

178 阅读2分钟

首先,Steam 操作,是分类的。总体上分为两大类,即中间操作(Intermediate operations)和结束操作(Terminal operations)。同时需要注意,还有一种特殊的操作即 Short circuiting 操作,中间操作和结束操作中都有这种操作。

图片.png

图片.png

short-circuit

关于 short-circuit 操作,我们可以参考普通的 boolean short-circuiting 逻辑,举个例子, firstBoolean && secondBoolean ,如果 firstBoolean 是 false,那么剩下的部分就会被忽略掉(也就是说,操作被短路了),因为剩下的表达式,按理说就会被废弃掉。在 Stream 中,short-circuit 操作逻辑是类似的,但其不仅限于 boolean 类型。

我们下面举个例子来说明一下 short-circuit

Stream<T> limit(long maxSize)
// 首先我们定义一个数组
int[] ints = {1, 2, 3, 4, 5, 6};

// 然后我们用不同的 Stream 来进行处理
Arrays.stream(ints).filter(i -> i % 2 == 0)
              .forEach(System.out::println);

Arrays.stream(ints).filter(i -> i % 2 == 0)
              .limit(2)
              .forEach(System.out::println);
              
// 输出结果
 2
 4
 6

 2
 4

从上面的结果我们可以看出,在使用来 .limit(2) 后,第二个元素之后的元素就不再处理了。而且这是我们在 Stream 中目前唯一的一个 Intermediate short-circuiting method,既然说了 Intermediate ,那么肯定就有 Terminal 操作,不过在这之前有一个点需要注意 ⚠️ 一个 Stream 在 terminal 操作后,不能被重复使用。

我们再举个例子来说明一下用法

Stream<T> limit(long maxSize)

IntStream stream = IntStream.of(1, 2, 3, 4, 5, 6);
   stream = stream.filter(i -> i % 3 == 0);
   OptionalInt opt = stream.findFirst();
   if (opt.isPresent()) {
       System.out.println(opt.getAsInt());
   }

//输出
3

除了以上的例子,上面的图里也有更多其他的 Terminal short-circuiting method,在使用的时候按需使用即可。

Intermediate operations & Terminal operations

Intermediate operations 只是对操作进行了记录,只有操作结束的时候才会触发实际的计算。中间操作中又分为无状态(Stateless)和有状态(Stateful)操作,区别就在于,前者指元素的处理不受之前元素的影响,后者是指只有拿到所有的元素后才能继续下去。

Terminal operations 操作结束后会触发实际计算,在最后计算的时候,会把所有的中间操作积攒起来的操作,以 pipline 的方式进行执行,这样就可以减少迭代次数,并且执行后 stream 会失效。