Stream的常用API应用场景
速记
目标 | 一口流利的 API |
---|---|
过滤 | .filter(Predicate) |
转换 | .map(Function) |
一对多展开 | .flatMap(Collection::stream) |
分组 | Collectors.groupingBy |
去重合并 | Collectors.toMap(key, value, mergeFn) |
防空指针 | Optional.ofNullable(..).map(..).orElse |
调试 | .peek(System.out::println) |
详解
你看到的方法 | 属于哪个 API | 背后的函数式接口 |
---|---|---|
.stream() | Collection 接口(1.8 默认方法) | 无,只是个入口 |
.filter(...) | Stream 接口 | Predicate<T> |
.map(...) | Stream 接口 | Function<T,R> |
.collect(Collectors.xxx) | Stream 接口 | 各种 Collector 实现 |
Optional.ofNullable(...) | java.util.Optional | Consumer 、Function 、Supplier |
List<String> upper =names.stream() // 1. 入口:Collection.stream().filter(s -> s != null) // 2. filter 属于 Stream API,参数是 Predicate 函数式接口.map(String::toUpperCase) // 3. map 属于 Stream API,参数是 Function 函数式接口.collect(Collectors.toList()); // 4. collect 属于 Stream API,Collector 工具类
- Stream API 负责“流水线”语法:.stream()、.filter()、.map()、.collect()。
- 函数式接口 负责“把代码当数据传”:s -> s != null、String::toUpperCase。
LEVEL-1 扔掉 for-each
把“循环”变成“管道”:源 → 中间操作 → 收集。
List<Result> result = list.stream() // 源.filter(Objects::nonNull) // 中间.map(this::toResult) // 中间.collect(Collectors.toList()); // 收集
- 常见坑
忘记 collect——流是“蓝图”,不收集就不会执行。
LEVEL-2 搞定分组/去重/统计
收集器 Collectors 就是“SQL 里的 GROUP BY、DISTINCT、COUNT”。
// 分组
Map<K, List<T>> group = list.stream().collect(Collectors.groupingBy(T::getK));// 去重(按 key)
Map<K, T> unique = list.stream().collect(Collectors.toMap(T::getK, // keyFunction.identity(), // value(old, nw) -> nw)); // 冲突留新// 统计
IntSummaryStatistics st = list.stream().collect(Collectors.summarizingInt(T::getScore));
int max = st.getMax();
- 常见坑
toMap 遇到重复 key 直接抛异常;必须给第三个参数(合并函数)。
LEVEL-3 链式 Optional + 自定义收集器
Optional 当“防空指针链”,自定义收集器当“通用算法模板”。
// 防空指针链
String name = Optional.ofNullable(dto).map(DTO::getOrder).map(Order::getCustomer).map(Customer::getName).orElse("UNKNOWN");// 自定义收集器:把 stream → LinkedHashSet(保持顺序又去重)
Collector<Integer, ?, Set<Integer>> orderedDistinct =Collector.of(LinkedHashSet::new, // 供应器Set::add, // 累加器(left, right) -> { left.addAll(right); return left; }, // 组合器Function.identity()); // 完成器
Set<Integer> orderNoDup = nums.stream().collect(orderedDistinct);
- 常见坑
Optional 不要 get() 直接拆包;用 orElse/orElseThrow 结束。
自定义收集器里,如果容器是线程不安全(如 ArrayList),千万别并行 parallelStream()。