面试官问:
你有用过Java的流式吗?比如说一个列表.stream这种,然后以流式去处理数据。
Stream是个啥?
说白了,Stream就是Java8给我们提供的、专门处理集合数据的流水线工具 。
它不是集合,不存数据,也不改你原来的集合,就是给你搭了一条加工数据的流水线:
你把集合丢进去,经过过滤、转换、排序这些工序,最后输出你想要的结果。
两个特性
- 惰性求值(延迟执行)
你写的filter、map这些中间操作,写完不会立刻执行,只是记下来你要做什么。
只有你写了最后一步的collect、count这种终端操作,整个流水线才会一次性跑完。
好处就是性能好,不用多次遍历集合,还能做优化。
- 一次性消费
一个Stream流只能用一次,跑完终端操作就关了,想再用就得重新从集合创建新的流,不然会直接报错。
一个标准的Stream流程
- 创建流
从集合、数组里拿到Stream对象,最常用的就是list.stream();
- 中间操作
加工数据,比如过滤、转换、排序,返回新的Stream,可以一直链式写下去;
- 终端操作
触发执行,拿到最终结果,比如收集成List、统计数量,跑完这步流就关了。
举个例子
就拿电商订单来说,需求是:
过滤已支付、金额大于100的订单,提取用户id去重,按金额倒序取前10,统计每个用户的总消费金额。
java
// 模拟订单列表
List<Order> orderList = initOrderList();
// 1. 过滤有效订单
List<Order> validOrderList = orderList.stream()
.filter(order -> order.getStatus() == 1) // 已支付
.filter(order -> order.getAmount().compareTo(new BigDecimal("100")) > 0) // 金额>100
.collect(Collectors.toList());
// 2. 提取用户id去重
Set<Long> userIdSet = validOrderList.stream()
.map(Order::getUserId)
.collect(Collectors.toSet());
// 3. 按金额倒序取前10
List<Order> top10OrderList = validOrderList.stream()
.sorted(Comparator.comparing(Order::getAmount).reversed())
.limit(10)
.collect(Collectors.toList());
// 4. 按用户分组统计总消费
Map<Long, BigDecimal> userTotalAmountMap = validOrderList.stream()
.collect(Collectors.groupingBy(
Order::getUserId,
Collectors.reducing(BigDecimal.ZERO, Order::getAmount, BigDecimal::add)
));