一、开发场景
书写查询相关业务代码时,需要调用微服务提供方返回的集合数据并对其进行筛选。比如筛选某字段与预期值匹配的所有数据。
// 服务提供方返回的集合数据
List<CentManlReimRegAndSetlDTO> list = pageResult.getData();
// 参与筛选的预期值
String medType = "xxx";
二、常规写法
/*
利用foreach循环数据并判断筛选,填入新的集合中
*/
List<CentManlReimRegAndSetlDTO> newList = new ArrayList<>();
for (CentManlReimRegAndSetlDTO dto : list) {
if(medType.equals(dto.getMedType())){
newList.add(dto);
}
}
return newList;
三、流操作写法
/*
将集合转换为流,筛选后再转集合
*/
List<CentManlReimRegAndSetlDTO> newList = list.stream()
.filter(dto -> medType.equals(dto.getMedType()))
.collect(Collectors.toList());
return newList;
filter方法的参数Predicate是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤。
四、总结
stream 相对于 Collection 的优点
- 无存储: 流并不存储值;流的元素源自数据源(可能是某个数据结构、生成函数或I/O通道等等),通过一系列计算步骤得到;
- 函数式风格: 对流的操作会产生一个结果,但流的数据源不会被修改;
- 惰性求值: 多数流操作(包括过滤、映射、排序以及去重)都可以以惰性方式实现。这使得我们可以用一遍遍历完成整个流水线操作,并可以用短路操作提供更高效的实现;
- 无需上界: 不少问题都可以被表达为无限流(infinite stream):用户不停地读取流直到满意的结果出现为止(比如说,枚举 完美数 这个操作可以被表达为在所有整数上进行过滤);集合是有限的,但流可以表达为无线流;
代码简练: 对于一些collection的迭代处理操作,使用 stream 编写可以十分简洁,如果使用传统的 collection 迭代操作,代码可能十分啰嗦,可读性也会比较糟糕;
stream 和 iterator 迭代的效率比较
传统 iterator (for-loop) 比 stream(JDK8) 迭代性能要高,尤其在小数据量的情况下;
- 在多核情景下,对于大数据量的处理,parallel stream 可以有比 iterator 更高的迭代处理效率;
即:
迭代方式:可读性差,数据量小时效率高
流操作方式:可读性好,数据量大、并行处理时效率高
参考资料: JDK 8 Stream 数据流效率 jdk8 lambda表达式list操作分组、过滤、求和、最值、排序、去重