本文目录导读:

在Java中使用Stream进行数据去重非常方便,主要通过distinct()方法或结合collect(Collectors.toCollection(...))实现,以下是几种常见场景的完整案例:
基础类型数据去重
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class BasicDistinctExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 4, 1, 5, 3);
// 使用distinct()去重
List<Integer> distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("原始数据: " + numbers);
System.out.println("去重后: " + distinctNumbers);
// 输出: [1, 2, 3, 4, 5]
}
}
字符串去重(不区分大小写)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StringDistinctExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("Apple", "banana", "apple", "Banana", "orange");
// 不区分大小写去重
List<String> distinctWords = words.stream()
.map(String::toLowerCase) // 统一转小写
.distinct()
.collect(Collectors.toList());
System.out.println("原始数据: " + words);
System.out.println("不区分大小写去重后: " + distinctWords);
// 输出: [apple, banana, orange]
}
}
对象去重 - 按指定字段
import java.util.*;
import java.util.stream.Collectors;
// 学生类
class Student {
private int id;
private String name;
private int age;
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() { return id; }
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() {
return "Student{id=" + id + ", name='" + name + "', age=" + age + "}";
}
}
public class ObjectDistinctExample {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(1, "Alice", 20),
new Student(2, "Bob", 22),
new Student(1, "Alice", 20), // 重复
new Student(3, "Charlie", 21),
new Student(2, "Bob", 23) // id重复但年龄不同
);
// 方案1:按id去重(使用TreeSet)
List<Student> distinctById = students.stream()
.collect(Collectors.collectingAndThen(
Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparingInt(Student::getId))
),
ArrayList::new
));
System.out.println("按id去重:");
distinctById.forEach(System.out::println);
// 输出两个学生:id=1和id=2(保留第一次出现的)
// 方案2:按姓名去重(使用toMap)
List<Student> distinctByName = students.stream()
.collect(Collectors.toMap(
Student::getName, // 键提取
student -> student, // 值提取
(existing, replacement) -> existing // 冲突处理:保留第一个
))
.values()
.stream()
.collect(Collectors.toList());
System.out.println("\n按姓名去重:");
distinctByName.forEach(System.out::println);
}
}
多字段组合去重
import java.util.*;
import java.util.stream.Collectors;
public class MultipleFieldDistinctExample {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(1, "Alice", 20),
new Student(2, "Bob", 22),
new Student(1, "Alice", 20), // 完全重复
new Student(1, "Bob", 22) // id和name重复
);
// 按id+name组合去重
List<Student> distinctByMultipleFields = students.stream()
.collect(Collectors.collectingAndThen(
Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(
(Student s) -> s.getId() + "-" + s.getName()
))
),
ArrayList::new
));
System.out.println("按id+name组合去重:");
distinctByMultipleFields.forEach(System.out::println);
// 输出: [Student{id=1, name='Alice', age=20}, Student{id=2, name='Bob', age=22}]
}
}
自定义去重(保留最新数据)
import java.util.*;
import java.util.stream.Collectors;
public class CustomDistinctExample {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(1, "Alice", 20),
new Student(2, "Bob", 22),
new Student(1, "Alice", 21), // id相同但年龄更新
new Student(3, "Charlie", 21)
);
// 按id去重,保留年龄最大的(即最新数据)
List<Student> distinctWithMaxAge = students.stream()
.collect(Collectors.toMap(
Student::getId,
student -> student,
(old, newStudent) -> old.getAge() >= newStudent.getAge() ? old : newStudent
))
.values()
.stream()
.collect(Collectors.toList());
System.out.println("按id去重(保留年龄最大的):");
distinctWithMaxAge.forEach(System.out::println);
// 输出: [Student{id=1, name='Alice', age=21}, Student{id=2, name='Bob', age=22}, ...]
}
}
处理null值的去重
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class NullSafeDistinctExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", null, "banana", "apple", null, "orange");
// 去重并过滤null
List<String> result = words.stream()
.filter(Objects::nonNull) // 先过滤null
.distinct()
.collect(Collectors.toList());
System.out.println("过滤null并去重: " + result);
// 输出: [apple, banana, orange]
// 如果要保留一个null
List<String> withNull = words.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("含null的去重: " + withNull);
// 输出: [apple, null, banana, orange]
}
}
常用去重方法总结
| 方法 | 适用场景 | 代码示例 |
|---|---|---|
distinct() |
基础类型、对象(需重写equals/hashCode) | list.stream().distinct() |
toCollection(TreeSet) |
按指定字段去重 | Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(对象::get字段))) |
toMap() |
复杂去重逻辑(保留最新、保留第一个等) | Collectors.toMap(键提取, 值提取, 冲突处理) |
最佳实践建议:
- 简单类型去重用
distinct() - 对象去重用
TreeSet或toMap方法 - 需要复杂逻辑(如保留最新)用
toMap重载方法