java stream去空去重需先filter(objects::nonnull)再distinct()或tomap,对象字段去重推荐tomap+linkedhashmap保序,通用工具方法可用concurrenthashmap.newkeyset()实现线程安全去重。

Java Stream API 实现去重和去空,本质是两个独立但常连用的操作:去空(过滤 null 值)用 filter(Objects::nonNull),去重(按需)可用 distinct() 或更灵活的字段级去重。关键在于顺序和语义——必须先去空再去重,否则 null 可能触发 NPE 或干扰去重逻辑。
基础去空 + 元素级去重
适用于字符串、数字等基本类型,或已正确重写 equals() 和 hashCode() 的对象:
- 先用
filter(Objects::nonNull)排除 null 元素 - 再调用
distinct()利用元素自身相等性去重 - 最后收集为 List 或其他容器
示例:
List.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
对象按字段去重(同时去空)
对自定义对象(如 User),需根据某字段(如 id、name、email)去重,且跳过 null 对象:
- 必须前置
filter(Objects::nonNull),避免后续 keyExtractor 调用空指针 - 推荐使用
Collectors.toMap:以字段为 key,对象为 value,冲突时保留首个((old, new) -> old) - 用
LinkedHashMap::new保证原始顺序
示例(按 name 去重):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
.filter(Objects::nonNull)
.collect(Collectors.toMap(
User::getName,
Function.identity(),
(old, new) -> old,
LinkedHashMap::new
)).values()
.stream().collect(Collectors.toList());
通用字段去重工具方法(支持去空)
封装一个可复用的 Predicate,内部自动跳过 null,并线程安全地记录已见 key:
- 定义静态方法
distinctByKey(Function super T, ?> keyExtractor) - 内部用
ConcurrentHashMap.newKeySet()存 key,避免并发问题 - 调用时仍需显式 filter null,或在 predicate 内部加判空(更健壮)
增强版写法(含空值防护):
private staticSet
去空去重后保持顺序的注意事项
Stream 默认保持 encounter order(遭遇顺序),但部分操作会破坏它:
-
distinct()在串行流中保持顺序;并行流中不保证 -
toMap若未指定LinkedHashMap::new,默认用 HashMap,顺序丢失 -
TreeSet方案虽有序,但依赖 Comparator,且天然不保留原始插入顺序
因此,如需严格保序,优先选 toMap + LinkedHashMap,或串行流 + distinct() + 显式 filter null。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










