list去重stream去重多个字段
时间: 2025-03-25 11:17:54 AIGC 浏览: 71
### 如何在 Java Stream 中根据多个字段对 List 进行去重
在 Java 的 `Stream` API 中,默认的 `distinct()` 方法基于对象的 `hashCode()` 和 `equals()` 实现来去除重复项[^2]。然而,如果需要根据特定字段组合来进行去重,则可以通过自定义逻辑实现这一功能。
以下是通过 `Collectors.toMap` 或者 `filter` 结合 lambda 表达式的解决方案:
#### 使用 Collectors.toMap 去重
可以利用 `toMap` 收集器的功能,在收集过程中保留唯一的键值对,并丢弃重复条目。这种方法适用于需要根据多个字段进行比较的情况。
```java
import java.util.*;
import java.util.stream.Collectors;
class Record {
private int id;
private String name;
public Record(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Record{id=" + id + ", name='" + name + "'}";
}
}
public class Main {
public static void main(String[] args) {
List<Record> records = Arrays.asList(
new Record(1, "Alice"),
new Record(2, "Bob"),
new Record(1, "Alice"), // Duplicate based on (id, name)
new Record(3, "Charlie")
);
List<Record> distinctRecords = records.stream()
.collect(Collectors.collectingAndThen(
Collectors.toMap(
record -> Arrays.asList(record.getId(), record.getName()), // Composite key
record -> record,
(existing, replacement) -> existing), // Resolve duplicates by keeping the first occurrence
map -> new ArrayList<>(map.values())
));
System.out.println(distinctRecords);
}
}
```
上述代码中,复合键由 `Arrays.asList(record.getId(), record.getName())` 构造而成,从而实现了多字段联合判断唯一性的需求[^1]。
---
#### 使用 filter 方法配合 Set 去重
另一种方法是借助一个外部集合(如 `Set`),记录已经处理过的键值组合,并过滤掉重复的数据。
```java
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<Record> records = Arrays.asList(
new Record(1, "Alice"),
new Record(2, "Bob"),
new Record(1, "Alice"), // Duplicate based on (id, name)
new Record(3, "Charlie")
);
Set<List<Object>> seenKeys = new HashSet<>();
List<Record> distinctRecords = records.stream()
.filter(record -> {
List<Object> key = Arrays.asList(record.getId(), record.getName());
return seenKeys.add(key); // Add returns false if already present
})
.collect(Collectors.toList());
System.out.println(distinctRecords);
}
}
```
此方案的核心在于维护了一个 `seenKeys` 集合,用于跟踪已遇到的对象属性组合。当尝试向该集合添加新键时,若返回值为 `false` 则表示当前对象已被处理过并应被跳过。
---
#### 性能对比与适用场景分析
- **`Collectors.toMap` 方案**:适合于最终结果不需要保持原始顺序的情形;内部使用哈希表存储临时映射关系。
- **`filter` 加上 `Set` 方案**:能够较好地支持流操作中的短路特性,同时允许灵活调整筛选条件;特别推荐在需维持输入列表原有次序的情况下采用。
无论哪种方式都达到了依据指定字段完成去重的目的,具体选用哪一种取决于实际业务需求以及性能考量因素。
---
阅读全文
相关推荐



















