外观
一句话答案
Lambda 是匿名函数简写(函数式接口的实例),Stream 提供声明式集合操作(filter/map/reduce),支持惰性求值和并行处理。
核心要点
Stream 的三段式结构:
数据源 → 中间操作(惰性,不立即执行)→ 终端操作(触发实际计算)常用中间操作(返回 Stream,惰性求值):
java
stream.filter(x -> x > 10) // 过滤
.map(x -> x * 2) // 映射转换
.flatMap(list -> list.stream()) // 扁平化(一对多映射)
.distinct() // 去重
.sorted() // 排序
.peek(System.out::println) // 调试窥探(不影响数据)
.limit(10) // 取前 N 个
.skip(5) // 跳过前 N 个常用终端操作(触发计算,返回结果):
java
stream.forEach(System.out::println) // 遍历
stream.collect(Collectors.toList()) // 收集为 List
stream.collect(Collectors.groupingBy(x::getType)) // 分组
stream.reduce(0, Integer::sum) // 归约
stream.count() // 计数
stream.anyMatch(x -> x > 10) // 是否存在匹配
stream.findFirst() // 取第一个(返回 Optional)
stream.toArray() // 转数组惰性求值(Lazy Evaluation):
java
// 中间操作不会立即执行,只有终端操作触发时才真正计算
List<String> result = names.stream()
.filter(name -> {
System.out.println("filter: " + name); // 如果没有终端操作,这行永远不会打印
return name.length() > 3;
})
.map(String::toUpperCase)
.collect(Collectors.toList()); // 终端操作触发整个管道执行
// 优势:短路操作(如 findFirst)可以提前终止,不会遍历所有元素
Optional<String> first = names.stream()
.filter(name -> name.startsWith("A"))
.findFirst(); // 找到第一个就停止,不会继续 filter 后面的元素Stream 的常见面试编码题:
java
// 1. 按部门分组并统计平均薪资
Map<String, Double> avgSalary = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.averagingDouble(Employee::getSalary)
));
// 2. 扁平化嵌套集合并去重
List<String> allTags = articles.stream()
.flatMap(article -> article.getTags().stream())
.distinct()
.sorted()
.collect(Collectors.toList());
// 3. 找出薪资 Top3 的员工名
List<String> top3 = employees.stream()
.sorted(Comparator.comparingDouble(Employee::getSalary).reversed())
.limit(3)
.map(Employee::getName)
.collect(Collectors.toList());parallelStream 的注意事项:
① 底层使用 ForkJoinPool.commonPool()(默认线程数 = CPU 核数 - 1)
② 不适合 IO 密集型操作(阻塞公共线程池,影响整个应用)
③ 有线程安全问题:不要在 forEach 中操作共享可变状态
④ 适合:大数据量的 CPU 密集型计算(如排序、统计)
⑤ 不适合:数据量小(线程切换开销 > 并行收益)、有序要求强的场景文档完
复习建议:
- ConcurrentHashMap JDK7 vs JDK8 必须熟背,这是面试高频对比题
- HashMap put 流程要能完整口述(hash计算 → 定桶 → 冲突处理 → 树化 → 扩容)
- epoll 相比 select/poll 的优势是网络/IO 相关题的通用基础,Redis 快、Netty 高性能都源于此
- Record / Sealed Classes / Virtual Threads 是 Java 17-21 面试新热点,尤其在要求 JDK 17+ 的岗位中高频出现
- 泛型 PECS 原则(Q27)配合 Collections 源码理解效果最好;反射+动态代理(Q28)是理解 Spring AOP 的前置知识
- Stream 编码题(Q29)建议手写 groupingBy + flatMap + sorted 组合链,面试现场写的概率很高
追问与易错
追问方向:
- Stream ��惰性求值的吗?(中间操作惰性,终端操作触发执行)
- parallelStream 有什么坑?(共享 ForkJoinPool/线程安全/有序性)
- Lambda 捕获变量有什么限制?(effectively final)
易错点:
- ❌ "parallelStream 一定比串行快"——小数据量或简单操作反而慢(线程开销)
- ❌ Stream 操作后原始集合不变——Stream 不修改源数据
💡 记忆锚点
Stream是流水线:中间操作(filter/map/flatMap)只画图纸不开工(惰性),终端操作(collect/reduce)按下启动键才真正跑。parallelStream共用公共线程池,IO密集型别用它堵车。