最常用且安全的集合筛选方式是stream().filter(),它支持链式调用和延迟执行,但需确保集合非null并显式collect;removeIf()会修改原集合,适用于就地删除;Guava过滤已过时,应优先使用Stream API。

用 stream().filter() 是最常用也最安全的方式
Java 8 引入的 Stream API 让集合筛选变得直观,且天然支持链式调用和延迟执行。只要集合不是 null,stream() 方法在 Collection 接口里已默认提供,无需额外依赖。
常见错误是直接对 null 集合调用 stream(),会抛出 NullPointerException;另一个坑是误以为 filter() 会修改原集合——它不会,返回的是新 Stream,需显式收集(如用 collect(Collectors.toList()))。
- 筛选字符串长度大于 3 的元素:
list.stream().filter(s -> s != null && s.length() > 3).collect(Collectors.toList());
- 注意判空:lambda 中最好先检查
s != null,尤其当原始集合可能含null值时 - 性能提示:如果只是找“第一个匹配项”,用
findFirst()比collect()更高效
修改原集合要用 removeIf(),但有副作用风险
removeIf() 是 Collection 接口的默认方法,直接遍历并移除满足条件的元素,会改变原集合。它比手动写 for 循环 + Iterator.remove() 更简洁,但要注意并发修改异常和逻辑耦合问题。
典型误用:在增强 for 循环中调用 removeIf() —— 虽然语法合法,但容易引发理解混乱;更严重的是,在多线程环境下直接调用 removeIf() 到非线程安全集合(如 ArrayList),会导致 ConcurrentModificationException 或数据不一致。
立即学习“Java免费学习笔记(深入)”;
- 安全写法:
list.removeIf(s -> s == null || s.isEmpty());
- 不可用于不可变集合(如
Collections.unmodifiableList()),会抛UnsupportedOperationException - 若需保留原集合不变,绝不能用
removeIf(),必须走stream().filter()路线
第三方库如 Guava 的 Iterables.filter() 已基本过时
Guava 19+ 开始明确标记 Iterables.filter() 为 @Deprecated,推荐迁移到 Java 自带的 Stream。它的返回类型是 Iterable,不支持链式终止操作(如 count()、anyMatch()),且底层仍基于迭代器,无法短路或并行化。
除非你被卡在 Java 7 环境,否则不要为过滤专门引入 Guava。即使已有 Guava 依赖,也应避免混用两套过滤风格,增加维护成本。
- 旧写法(不推荐):
Iterables.filter(list, s -> s.length() > 5);
- 替代写法:
list.stream().filter(s -> s.length() > 5).toList(); // Java 16+
或list.stream().filter(...).collect(Collectors.toList()); // 兼容旧版
- Guava 的
Predicates工具类同理,已无必要使用
数组或原始类型集合需额外转换
Java 的 stream() 对原始数组(如 int[])不直接支持,也不能对基本类型集合(如 int)自动装箱后流畅过滤。这是新手常卡住的地方。
比如想筛选出 int[] 中所有偶数,不能写 Arrays.stream(arr).filter(i -> i % 2 == 0) —— 这样得到的是 IntStream,再调 collect() 会编译失败,因为没有对应的基本类型收集器。
- 正确做法(转为包装类再处理):
Arrays.stream(arr).boxed().filter(i -> i % 2 == 0).collect(Collectors.toList());
- 更高效做法(保持原始类型):
int[] evens = Arrays.stream(arr).filter(i -> i % 2 == 0).toArray();
- 对于
List,直接用stream()即可,无需额外处理;但注意装箱开销在高频场景下不可忽略
null」这两个前提——它们直接决定该选 filter() 还是 removeIf(),以及是否要加空校验。写之前花三秒想清楚这点,能省掉一半调试时间。










