Stream.filter 不改变原List,因返回新Stream且惰性求值;必须collect才能落地结果,toList()返回不可变列表,需可变时用toCollection(ArrayList::new);filter不自动处理null,应显式检查。

Stream.filter 为什么不能直接修改原 List
因为 Stream.filter 返回的是一个新 Stream,不是原集合的引用,更不会改变原始 List。常见错误是调用完 filter 就以为原列表已被“筛掉”了不符合条件的元素——其实什么都没变。
必须显式收集结果,否则过滤操作根本没落地。典型误写:
list.stream().filter(x -> x > 10); // 没有 .collect(),这行代码毫无副作用
- 必须链式调用
collect(Collectors.toList())或其他收集器才能拿到结果 - 原
List始终不变,这是函数式操作的默认行为 - 如果需要就地修改(不推荐),得用传统 for 循环 +
Iterator.remove()
collect 时选 toList() 还是 toCollection(ArrayList::new)
Java 16+ 的 Collectors.toList() 返回的是不可变 List(ImmutableCollections.ListN),一旦后续要 add、remove 就会抛 UnsupportedOperationException。这点常被忽略,尤其在测试或调试中临时往结果里加元素时突然崩掉。
基于 AIOZ Stream API 的免费音频上传技能,通过三步流程(Create → Upload Part → Complete)将本地音频文件上传至 AIOZ 流媒体平台。支持默认快速上传方式,使用默认编码配置,上传完成后返回 HLS 流媒体播放链接。使用 API Key (stream-publ...)进行认证。
- 要可变列表:用
collect(Collectors.toCollection(ArrayList::new)) - 只读场景(如传参、遍历):
toList()更轻量,且明确表达“不打算改” - 注意
toCollection(LinkedList::new)等写法也合法,按需选择底层实现
空值处理:filter 前要不要先判 null
filter 本身不会自动跳过 null,如果元素可能为 null,而你的谓词(Predicate)里又直接调用了 .equals() 或 .length(),就会触发 NullPointerException。
- 安全写法:把 null 检查放进 filter 条件,比如
filter(x -> x != null && x.startsWith("A")) - 或者提前用
filter(Objects::nonNull)过滤掉 null,再接其他逻辑 - 别依赖“数据肯定不为空”——生产环境总有意外
性能陷阱:filter 后立即 collect 还是留到后面
Stream 是惰性求值的,但一旦调用 collect,整个流水线就会从头执行一次。如果反复对同一 Stream 调用 collect(比如误写成两次),会报 IllegalStateException: stream has already been operated upon。
- 每个 Stream 只能被消费一次;重复使用需重新生成:
list.stream().filter(...).collect(...) - 不要为了“复用”而缓存 Stream 对象,它不是可重入资源
- 大数据量下,避免在 filter 中做耗时操作(如远程调用、文件读取),否则性能雪崩
实际用的时候,最常卡住的不是语法,而是忘了 collect、误判了返回集合的可变性、或者没兜底 null —— 这三处不检查,线上跑两小时才暴露问题。










