java使用 Stream 流对自定义对象数组去重的
在 Java 中,使用 Stream 流对自定义对象数组去重的核心是确保对象能正确判断“重复”的逻辑。以下是具体实现方法及场景分析:
方法 1:直接使用 distinct()
(需重写 equals
和 hashCode
)
若自定义对象已正确重写 equals()
和 hashCode()
方法,可直接通过 distinct()
去重。
适用场景:对象的唯一性由所有字段共同决定(如数据库实体类的主键)。
示例代码
public class Person {private String id;private String name;// 构造方法、Getter/Setter 省略@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return Objects.equals(id, person.id); // 根据 id 判断是否相等}@Overridepublic int hashCode() {return Objects.hash(id); // 基于 id 生成哈希}
}// 使用 Stream 去重
Person[] people = ...; // 自定义对象数组
List<Person> uniqueList = Arrays.stream(people).distinct().collect(Collectors.toList());
方法 2:基于对象的某个唯一属性去重(无需重写 equals
和 hashCode
)
若无法修改对象类(如第三方库的类),或需根据部分字段去重,可用 Collectors.toMap
或 TreeSet
实现。
(1) 使用 Collectors.toMap
适用场景:根据唯一键(如 id
)去重,保留第一个出现的元素。
List<Person> uniqueList = Arrays.stream(people).collect(Collectors.toMap(Person::getId, // Key 提取函数(根据 id 去重)p -> p, // Value 为对象本身(existing, replacement) -> existing // 冲突时保留已存在的元素)).values() // 获取去重后的 Value 集合.stream().collect(Collectors.toList());
(2) 使用 TreeSet
自定义比较器
适用场景:需要根据多个字段去重,或动态指定去重规则。
List<Person> uniqueList = Arrays.stream(people).collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(p -> p.getId() + p.getName())))).stream().collect(Collectors.toList());
方法 3:使用 filter
+ 内存状态去重
适用场景:需根据动态条件去重(如去重后保留最后一个元素)。
(1) 使用 ConcurrentHashMap
维护状态
Set<String> seenIds = ConcurrentHashMap.newKeySet();
List<Person> uniqueList = Arrays.stream(people).filter(p -> seenIds.add(p.getId())) // 若 id 未出现过,保留.collect(Collectors.toList());
(2) 保留最后一个出现的元素
List<Person> uniqueList = Arrays.stream(people).collect(Collectors.toMap(Person::getId,p -> p,(oldValue, newValue) -> newValue // 冲突时保留新元素)).values().stream().collect(Collectors.toList());
总结回答
- 直接去重:若对象重写了
equals()
和hashCode()
,直接用distinct()
。 - 按属性去重:使用
Collectors.toMap
或TreeSet
,根据唯一键(如id
)过滤。 - 动态去重:通过
filter
配合内存集合(如ConcurrentHashMap
)控制去重逻辑。
关键点:明确业务中“重复”的定义(如全字段相等或部分字段相等),选择性能与代码简洁性兼顾的方案。