项目场景:
java stream distinct根据list某个字段去重,普通List简单去重:
import java.util.Arrays;import java.util.List;import java.util.stream.Collectors;public class TestMain {public static void main(String[] args) { List<String> names = Arrays.asList("张三", "李四", "王五", "张三", "李四"); // 使用Stream的distinct()方法进行去重操作 List<String> distinctNames = names.stream().distinct().collect(Collectors.toList()); System.out.println("原始列表:" + names); System.out.println("去重后的列表:" + distinctNames); }}
很显然这种满足不了需求,我们List里的是实体对象,这里的是字符串。
前提基础:
首先创建了一个Student类,该类包含id、name、age三个字段,使用了注解@Data,我们想根据学生的name去重。
import lombok.Data;@Datapublic class Student { public Student(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;} private Integer id; private String name; private Integer age;}
解决方案:
一、Stream流 + TreeSet(推荐)
根据学生的name去重,原理:
1、首先使用Stream API对list进行转换成流,使用toCollection方法将流中的元素放入一个TreeSet集合中,通过TreeSet实现对name字段去重;
2、然后使用collectingAndThen方法将TreeSet集合转换成ArrayList集合;
用普通的list对象来操作需要分为两步操作,这里我们使用了Stream API提供的collect方法和Collectors类的两个静态方法toCollection和collectingAndThen来进行去重操作,不需要写繁琐的for循环,更加简洁高效。
import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.TreeSet;import java.util.stream.Collectors;public class TestMain {public static void main(String[] args) {List<Student> list = new ArrayList<>();list.add(new Student(1, "张三", 13));list.add(new Student(2, "李四", 14));list.add(new Student(3, "张三", 15));list.add(new Student(4, "王五", 16));list.add(new Student(5, "李四", 17));List<Student> distinctList = list.stream().collect( Collectors.collectingAndThen( Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getName))), ArrayList<Student>::new));System.out.println(distinctList); }}
二、Stream流 + toMap
根据学生的name去重,原理:
1、首先使用Stream API对list进行转换成流,使用Collectors.toMap方法将对象流转换为 Map,其中键是 name 字段,值是对象本身。当遇到重复的键时,我们使用合并函数 (p1, p2) -> p1 来选择保留哪个值;
2、然后通过提取 Map 的值集合,我们获得了去重后的结果。将集合转换成List集合;
用普通的list对象来操作需要分为两步操作,这里我们使用了Stream API来操作,不需要写繁琐的for循环,更加简洁高效。注意Map集合是无序的,所以最后打印的结果是无序的。
import java.util.ArrayList;import java.util.List;import java.util.function.Function;import java.util.stream.Collectors;public class TestMain {public static void main(String[] args) {List<Student> list = new ArrayList<>();list.add(new Student(1, "张三", 13));list.add(new Student(2, "李四", 14));list.add(new Student(3, "张三", 15));list.add(new Student(4, "王五", 16));list.add(new Student(5, "李四", 17));List<Student> distinctList = list.stream() .collect(Collectors.toMap(Student::getName, Function.identity(), (p1, p2) -> p1)) .values() .stream() .collect(Collectors.toList());System.out.println(distinctList); }}
三、重写equals和hashCode
Student类在原来的基础上,重写equals和hashCode,根据学生的name去重
import java.util.Objects;import lombok.Data;@Datapublic class Student { public Student(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;} private Integer id; private String name; private Integer age; // 重写 equals 和 hashCode 方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(name); }}
import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;public class TestMain {public static void main(String[] args) {List<Student> list = new ArrayList<>();list.add(new Student(1, "张三", 13));list.add(new Student(2, "李四", 14));list.add(new Student(3, "张三", 15));list.add(new Student(4, "王五", 16));list.add(new Student(5, "李四", 17));List<Student> distinctList = list.stream().distinct().collect(Collectors.toList());System.out.println(distinctList); }}