Stream 流“盲”

文摘   职场   2024-11-15 11:32   江苏  

今天又是有(da)意(jiang)义(you)一天,本想一把梭后下班走人,Bug突然造访,对于老江湖来说,这些都不叫事……


0.什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。

  • 数据源:流的来源。可以是集合,数组,I/O channel, 产生器generator 等。

  • 聚合操作: 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。


和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining:中间操作都会返回流对象本身。这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。

  • 内部迭代以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

Stream流作为Java 8引入的新特性之一, 封装一系列对单列集合/数组的操作的API,开发中操作确实方便了很多,如:Collectors.toMap、Collectors.toList、Collectors.groupingBy真的太香了,Respect

        

1. 作为一个有洁癖的猿类,有意识的不允许有重复的代码多次出现,这是一种高阶的职业素养,于是乎我遇到了她(bug),下面请欣赏

        

private Map<Integer, List<Engine>> method1(List<Car> cars) {    return cars.stream().            filter(car -> StatusEnum.NORMAL.getCode() == car.getStatus() &&                    !CollectionUtils.isEmpty(car.getEngines())).            collect(Collectors.toMap(Car::getId, Car::getEngines));}
public Map<Integer, Car> method2(List<Car> cars) { return cars.stream(). filter(car -> StatusEnum.NORMAL.getCode() == car.getStatus() && !CollectionUtils.isEmpty(car.getEngines())). collect(Collectors.toMap(Car::getId, Function.identity(), (k1, k2) -> k2));}

2. 仔(xian)细(de)分(dan)析(teng),上述method1的 Line2- 4 及method2 Line 9 -11 相同,都是先过滤掉不满足条件的数据后返回不同的结果,“为避免重复的浪费时间,如果能抽出来岂不更好,代码少了,时间也提升了

//将都有的抽成一个方法private Stream<Car> filter(List<Car> cars) {    return cars.stream().            filter(car -> StatusEnum.NORMAL.getCode() == car.getStatus() &&                    !CollectionUtils.isEmpty(car.getEngines()));}
private Map<Integer, List<Engine>> method1(Stream<Car> stream) { return stream.collect(Collectors.toMap(Car::getId, Car::getEngines));}
public Map<Integer, Car> method2(Stream<Car> stream) { return stream.collect(Collectors.toMap(Car::getId, Function.identity(), (k1, k2) -> k2));}

3. 编译都没问题,通常说明这样做是“合理的”!!!我可真是个小机灵鬼,让同学等我一下,我还有一分钟搞定,接下来以最快的速度:

git pull 

git commit -m '显著性能优化'

git push

spug打包、重启、见证奇(fan)迹(che)的时刻 


4. 一大瓶爽歪歪送过来,毛都不抖一下,从异常来看定位问题花了1纳秒,肯定跟自作聪明有关,又花了2微秒百度,紧接着花了3秒钟滚动鼠标看到结论:

所有的流对象只能使用一次”。


5. 基于4要解决这个问题就是还原回去,但这不是我要的,我想知道Why?


通过源码发现,针对流有两种操作(翻译可能不准,可意会就行):

中间操作:不改变Stream中元素信息,不产生结果;eg:sorted\map\filter

终端操作:会产生结果(意思是关闭了流返回了一个结果);eg:count\collect


---------------------------------------我是有底线的------------------------------------------


P.S:看到这还能怎么办,改回去!!!改?那是不可能的,至少今天晚上不可能,溜了,溜了,下次见


---------------------------------------我真的是有底线的-----------------------------------




晚霞程序员
一位需要不断学习的30+程序员……