stream.filter() 未生效主因是未触发终端操作,filter() 惰性执行且返回新 stream;map() 一对一转换,flatmap() 一对多压平;tolist()/toset() 非线程安全,并行流中顺序不保证;源自 i/o 的 stream 必须 close,集合 stream 无需。

Stream.filter() 为什么没生效?常见过滤失效原因
调用 filter() 后原集合不变,返回的是新 Stream —— 这是最常踩的坑。Stream 是惰性求值的,不触发终端操作(如 collect()、forEach())时,filter() 根本不会执行。
- 错误写法:
list.stream().filter(x -> x > 5);→ 没有任何效果,也没报错 - 正确写法:
List<integer> result = list.stream().filter(x -> x > 5).collect(Collectors.toList());</integer> - 如果只想判断是否存在满足条件的元素,用
anyMatch();想取第一个,用findFirst(),别漏掉终端操作 - 注意:
filter()的谓词函数不能返回null,否则抛NullPointerException,对可能为 null 的字段建议先用Objects.nonNull()判断
map() 和 flatMap() 的本质区别在哪
map() 是一对一转换,flatMap() 是一对多再压平。混淆二者会导致类型错误或嵌套结构意外加深。
-
map(s -> s.split(" "))返回Stream<string></string>,不是你想要的单词流 -
flatMap(s -> Arrays.stream(s.split(" "))才返回Stream<string></string> - 典型场景:
flatMap()处理 Optional(用optional.map(...).orElse(null)易空指针,改用optional.flatMap(...)更安全) - 性能提示:
flatMap()内部会创建多个 Stream 并合并,数据量大时注意 GC 压力
collect(Collectors.toList()) 和 toSet() 的线程安全性差异
toList() 和 toSet() 返回的集合默认都不是线程安全的,但更关键的是:它们在并行流中可能产生非确定性结果。
- 并行流下
collect(Collectors.toList())虽能运行,但顺序不保证(除非用Collectors.toCollection(ArrayList::new)+ 显式加锁,一般不推荐) - 想线程安全地累积结果,优先用
Collectors.collectingAndThen(..., Collections::unmodifiableList)封装,或直接用parallelStream().collect(ConcurrentHashMap::new, ...)自定义并发收集器 -
toSet()不保证迭代顺序,且底层用的是HashSet,同样非线程安全;若需有序去重,改用collect(Collectors.toCollection(LinkedHashSet::new))
Stream.close() 什么时候必须调用
仅当 Stream 源自 I/O 资源(如 Files.lines(path)、BufferedReader.lines())时才需要显式 close(),否则会泄露文件句柄。
立即学习“Java免费学习笔记(深入)”;
- 普通集合生成的 Stream(
list.stream())无需 close,也没 close 方法 - 带资源的 Stream 必须用 try-with-resources:
try (Stream<String> lines = Files.lines(Paths.get("log.txt"))) {<br> lines.filter(...).forEach(...);<br>} - 漏掉 close 的典型表现:Windows 下文件被占用无法删除,Linux 下出现 “Too many open files” 错误
- 注意:
Stream.iterate()或Stream.generate()创建的无限流,若没用limit()或takeWhile()终止,会 OOM —— 这和 close 无关,但容易一起被忽视










