Stream可简化代码但需规避副作用:filter()应使用纯函数条件,null需显式处理;forEach()禁用于并行流和状态修改,改用peek()或collect();map/flatMap宜组合使用,避免耗时操作;小集合或简单逻辑仍推荐传统循环。

能大幅简化代码,但必须注意函数式风格和副作用的冲突,否则会埋下并发或空指针隐患。
用 stream().filter() 替代 for + if 嵌套
传统写法里遍历集合再逐个判断,容易混入业务逻辑、状态修改,可读性差且难复用。用 filter() 可把「筛选条件」独立成纯函数,支持链式组合。
- 条件表达式必须是
Predicate<t></t>类型,比如user -> user.getAge() > 18,不能在里面调用System.out.println()或修改外部变量 - 原始集合不会被修改,
filter()返回的是新流,若需结果集合,得接collect(Collectors.toList()) - 空集合或 null 元素不会自动跳过——如果
user可能为 null,要写成Objects.nonNull(user) && user.getAge() > 18
用 stream().forEach() 替代增强 for 循环要注意副作用
forEach() 看似只是语法糖,但它在并行流(parallelStream())下不保证执行顺序,且禁止修改外部局部变量(除非是 final 或事实 final)。
- 想打印日志或发通知?用
peek()更合适,它专为「无副作用中间操作」设计,比如stream.peek(System.out::println).filter(...) - 要累积计算(如求和、拼字符串),别在
forEach里用StringBuilder拼接——改用collect()或reduce() - 避免在
forEach中抛出受检异常(如IOException),Lambda 不支持声明 throws,得用包装函数处理
当过滤后要映射或扁平化时,优先组合 filter() + map() + flatMap()
比起先 filter 再手动 for 遍历做转换,链式调用更清晰,也利于 JVM 优化(如短路、惰性求值)。
立即学习“Java免费学习笔记(深入)”;
-
map()适合一对一转换,比如users.stream().filter(u -> u.isActive()).map(User::getName) -
flatMap()处理一对多,比如每个用户有多个订单:users.stream().flatMap(u -> u.getOrders().stream()) - 别在
map()里做耗时操作(如 DB 查询),流本身不控制执行时机,可能意外触发多次——应提前预加载或用缓存
真正难的不是写对 Lambda,而是判断该不该用:集合小、逻辑简单、需要调试时,传统循环反而更直接;而涉及多条件组合、后续还要排序/分组/聚合时,Stream 链才是自然选择。别为了“函数式”硬套,尤其在老项目里混用迭代器和流,容易引发 ConcurrentModificationException。


















