在 Java Stream 中过滤 null 元素应使用 filter(Objects::nonNull),语义清晰且适用于所有泛型类型;filter(Objects::isNull) 仅用于保留 null 值,不适用于剔除场景;需避免在 filter 中嵌入业务逻辑或链式判空,应拆分 map 和 filter 操作。

在 Java Stream 中过滤 null 元素,核心是用好 Objects::nonNull 或 Objects::isNull,但二者语义和使用位置不同,不能混用。
filter(Objects::nonNull) 是最常用、最推荐的写法
它保留非 null 元素,语义清晰,符合 filter 的本意(“留下满足条件的”):
- 必须写成
filter(Objects::nonNull)—— 使用双冒号方法引用,不是filter(Objects.nonNull)(后者编译报错) - 适用于任意泛型类型:
List<String>、List<User>、List<Integer>都能直接用 - 它只判断元素引用是否为
null,不处理空字符串、空集合等逻辑空值 - 示例:
List<String> list = Arrays.asList("a", null, "b", null);List<String> result = list.stream().filter(Objects::nonNull).collect(Collectors.toList());
结果是["a", "b"]
filter(Objects::isNull) 一般不用在常规过滤场景
它的作用是“留下 null 元素”,日常业务中极少需要专门收集 null 值:
- 语法合法,但语义反直觉:比如
list.stream().filter(Objects::isNull).count()可用于统计 null 个数 - 若想剔除 null,绝不要写成
filter(Objects::isNull)后跟!filter(...)或取反逻辑——既绕又易错 - 真正要“删除 null”,应优先考虑
removeIf(Objects::isNull)(原地修改),而不是在 stream 里留着再取反
别把 filter 当成执行动作的地方
filter 只做判断,不负责计算。常见错误是把查找+判空塞进一个 filter 里:
立即学习“Java免费学习笔记(深入)”;
- ❌ 错误写法:
stream.filter(x -> service.findRelated(x) != null) - ✅ 正确拆分:
stream.map(x -> service.findRelated(x)).filter(Objects::nonNull) - 这样既避免重复调用,又让每步职责单一,也防止 findRelated 返回 null 时引发 NPE
注意源头 null 和链式字段判空
Objects::nonNull 只判第一层引用,对嵌套字段无效:
- 如果要过滤掉
user.getName() == null的用户,不能只写filter(Objects::nonNull) - 得写:
filter(u -> Objects.nonNull(u) && Objects.nonNull(u.getName())) - 更安全的做法是结合 Optional:
filter(u -> Optional.ofNullable(u).map(User::getName).isPresent())


















