文章目录
- 前言
- 流的定义
- 流简介
- 流与集合
- 只能遍历一次
- 流操作
- 使用流
- 总结
前言
Java 8引入了流操作,可以对数据进行命令式操作(与数据库类似的操作),使得代码可读性大大增强。同时,流的引入也减少了开发过程中的代码量,是对开发人员的福利。
流的定义
流允许用户以声明性方式处理数据集合,目前阶段可视为遍历数据集的高级迭代器。此外,流可以透明地并行处理。
// TODO: 筛选菜单中低热量的菜肴
// Java 7
List<Dish> lowCaloricDishes = new ArrayList<>();
for (Dish d : menu) {
if (d.getCalories() < 400) {
lowCaloricDishes.add(d);
}
}
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
public int compare(Dish d1, Dish d2) {
return Integer.compare(d1.getCalories(), d2.getCalories());
}
});
List<String> lowCaloricDishesName = new ArrayList<>();
for (Dish d : lowCaloricDishes) {
lowCaloricDishesName.add(d.getName());
}
// Java 8 Stream
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
List<String> lowCaloricDishesName = menu.stream()
// 选出400卡以下的菜
.filter(d -> d.getCalories() < 400)
// 按照卡路里排序
.sorted(comparing(Dish::getCalories))
// 提取菜肴名称
.map(Dish::getName)
// 将所有名称保存在List中
.collect(toList());
// 为了利用多核架构并行执行,只需要将 stream() 改为 parallelStream()
新方法的好处:
- 代码以声明性方式写的:说明想要完成什么而不是说明如何实现一个操作
- 可以将几个基础操作链接起来,来表达复杂的数据处理流水线
流简介
定义:从支持数据处理操作的源生成的元素序列
- 元素序列——和集合一样,流提供了一个接口,可以访问特定元素类型的一组有序值
- 源——流会使用一个提供数据的源头
- 数据处理操作——类似于数据库的操作,以及函数式编程语言中的常用操作
此外,流操作的两个特点:
- 流水线——流操作本身会返回一个流,多个操作可以链接起来
- 内部迭代
流与集合
粗略角度
差异:什么时候进行计算
- 集合:一个内存中的数据结构,包含数据结构中目前所有的值——集合中每个元素都得先算出来才能添加到集合中
- 流:概念上固定的数据结构(无法添加或删除元素),其元素是按需计算的。满足生产者-消费者的关系
只能遍历一次
流只能遍历一次,遍历完之后,流被销毁
List<String> title = Arrays.asList("Java8", "In", "Action");
Stream<String> s = title.stream();
// 打印标题中的每个单词
s.forEach(System.out::println);
// java.lang.IllegalStateException:流已被操作或关闭
s.forEach(System.out::println);
流操作
- 中间操作:可连接起来的流操作,例如 filter、map、limit
- 终端操作:关闭流的操作,例如 collect
使用流
使用流包括三件事:
- 一个数据源来执行一个查询;
- 一个中间操作链,形成 一条流的流水线;
- 一个终端操作,执行流水线,并能生成结果。
总结
本文介绍了流的概念,后续梳理了流与集合的差异,以及流的操作和注意事项。希望在后续开发中积极思考何时用流,如何用流,提升程序效率。