1. 概述
在开发中,我们经常需要从列表中筛选出不同的元素。Java 8 引入的 Stream API 为数据处理提供了函数式编程的新途径。
本文将展示如何基于对象特定属性对集合进行去重,涵盖标准 API 及第三方库的多种实现方案。
2. 使用 Stream API
Stream API 提供了 distinct()
方法,它基于对象的 equals()
方法实现去重。但当我们需要按特定属性去重时,这个方法就显得不够灵活了。
2.1. 使用有状态过滤器
一种解决方案是实现一个有状态的 Predicate
:
public static <T> Predicate<T> distinctByKey(
Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
测试时使用以下 Person
类(包含 age、email 和 name 属性):
public class Person {
private int age;
private String name;
private String email;
// 标准 getter/setter
}
按 name 属性去重的示例:
List<Person> personListFiltered = personList.stream()
.filter(distinctByKey(p -> p.getName()))
.collect(Collectors.toList());
✅ 这种方式无需引入额外依赖
⚠️ 但在并行流中需注意线程安全(已使用 ConcurrentHashMap 解决)
3. 使用 Eclipse Collections
Eclipse Collections 是一个为 Java 提供高级集合处理能力的库。
3.1. 使用 ListIterate.distinct()
ListIterate.distinct()
方法支持通过 HashingStrategies
按特定属性去重:
按 name 去重:
List<Person> personListFiltered = ListIterate
.distinct(personList, HashingStrategies.fromFunction(Person::getName));
对基本类型属性(如 int)有专门优化:
List<Person> personListFiltered = ListIterate.distinct(
personList, HashingStrategies.fromIntFunction(Person::getAge));
3.2. Maven 依赖
在 pom.xml 中添加:
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>8.2.0</version>
</dependency>
最新版本可在 Maven Central 查找。
4. 使用 Vavr (Javaslang)
这是一个为 Java 8 提供函数式数据结构的库。
4.1. 使用 List.distinctBy
Vavr 的 List
类提供 distinctBy()
方法支持按属性去重:
List<Person> personListFiltered = List.ofAll(personList)
.distinctBy(Person::getName)
.toJavaList();
4.2. Maven 依赖
在 pom.xml 中添加:
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.9.0</version>
</dependency>
最新版本可在 Maven Central 查找。
5. 使用 StreamEx
这个库扩展了 Java Stream API 的功能。
5.1. 使用 StreamEx.distinct
StreamEx
类提供了直接按属性去重的 distinct
方法:
List<Person> personListFiltered = StreamEx.of(personList)
.distinct(Person::getName)
.toList();
5.2. Maven 依赖
在 pom.xml 中添加:
<dependency>
<groupId>one.util</groupId>
<artifactId>streamex</artifactId>
<version>0.6.5</version>
</dependency>
最新版本可在 Maven Central 查找。
6. 总结
本文演示了在 Java 中按对象属性去重的多种方案:
- 标准 Stream API:适合简单场景,无需额外依赖
- Eclipse Collections:提供丰富的哈希策略,适合复杂场景
- Vavr:函数式编程风格,适合链式操作
- StreamEx:API 最简洁,直接支持属性去重
完整代码示例可在 GitHub 获取。根据项目需求选择合适方案,避免重复造轮子。