Java案例如何用Stream去重数据?

wen java案例 14

本文目录导读:

Java案例如何用Stream去重数据?

  1. 基础类型数据去重
  2. 字符串去重(不区分大小写)
  3. 对象去重 - 按指定字段
  4. 多字段组合去重
  5. 自定义去重(保留最新数据)
  6. 处理null值的去重
  7. 常用去重方法总结

在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()
  • 对象去重用 TreeSettoMap 方法
  • 需要复杂逻辑(如保留最新)用 toMap 重载方法

抱歉,评论功能暂时关闭!