Java8集合中的对象去重重复

1 使用的实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@String
public class User(){
	private String userId;
	private String userName;
	private Integer userAge;
}

2 利用Collectors.toMap去重

2.1 toMap去重说明

List<User> userList = new ArrayList<>();
        userList.add(new User("a", "xiaoming",12));
        userList.add(new User("b", "xiaoming",13));
        userList.add(new User("d", "xiaoming",15));
        userList.add(new User("a", "xiaoming",14));
       
        System.out.println("利用Collectors.toMap去重:");
        //利用Collectors.toMap去重
        userList.stream()
                .collect(Collectors.toMap(User::getUserId, 
                			Function.identity(), (oldValue, newValue) -> oldValue))
                .values()
                .stream()
                .forEach(System.out::println); //打印

输出结果:

[{"userAge":12,"userId":"a","userName":"xiaoming"},
{"userAge":13,"userId":"b","userName":"xiaoming"},
{"userAge":15,"userId":"d","userName":"xiaoming"}]

其中,Collectors.toMap需要使用三个参数的版本,前两个参数一个是keyMapper函数一个是valueMapper函数的,用过toMap的都知道,去重的关键在于第三个参数BinaryOperator函数接口。

这个BinaryOperator函数接收两个参数,如上面代码,一个oldValue,一个newValue,字面意思,第一个旧值,第二个是新值。当stream构造Map时,会先调用Map的get方法获取该key对应节点的旧值,如果该值为null,则不会调用BinaryOperator函数,如果不为null,则会把获取的旧值与新值作为参数传给函数执行,然后把函数的返回值作为新值put到Map中。如果看不懂,请看源码吧

2.2 Funcion.identity()解释

Java 8允许在接口中加入具体方法。接口中的具体方法有两种,default方法和static方法,identity()就是Function接口的一个静态方法
Function.identity()返回一个输出跟输入一样的Lambda表达式对象,等价于形如t -> t形式的Lambda表达式。
identity()方法JDK源码如下:

static  Function identity() {
    return t -> t;
}

下面的代码中,Task::getTitle需要一个task并产生一个仅有一个标题的key
task -> task是一个用来返回自己的lambda表达式,上例中返回一个task

private static Map<String, Task> taskMap(List<Task> tasks) {
  return tasks.stream().collect(toMap(Task::getTitle, task -> task));
}

可以使用Function接口中的默认方法identity来让上面的代码代码变得更简洁明了、传递开发者意图时更加直接,下面是采用identity函数的代码。

import static java.util.function.Function.identity;
private static Map<String, Task> taskMap(List<Task> tasks) {
  return tasks.stream().collect(toMap(Task::getTitle, identity()));
}

3 利用Collectors.toCollection和TreeSet去重

List<User> userList = new ArrayList<>();
        userList.add(new User("a", "xiaoming",12));
        userList.add(new User("b", "xiaoming",13));
        userList.add(new User("d", "xiaoming",15));
        userList.add(new User("a", "xiaoming",14));
       
        System.out.println("利用Collectors.toMap去重:");
        //利用Collectors.toMap去重
        userList.stream()
                .collect(Collectors.toCollection(() ->
                	 new TreeSet<>(Comparator.comparing(User::getUserId))))
                .values()
                .stream()
                .forEach(System.out::println); //打印

输出结果:

[{"userAge":12,"userId":"a","userName":"xiaoming"},
{"userAge":13,"userId":"b","userName":"xiaoming"},
{"userAge":15,"userId":"d","userName":"xiaoming"}]

利用TreeSet原理去重,TreeSet内部使用的是TreeMap,使用指定Comparator比较元素,如果元素相同,则新元素代替旧元素,
TreeMapput方法来放入元素的,有兴趣可以自己找源码
如果不想要返回TreeSet类型,那也可以使用Collectors.collectingAndThen转换成ArrayList,也可以用new ArrayList(set),原理一样,如下:

List<Person> distinctList = personList.stream()
                .collect(Collectors.collectingAndThen(Collectors.toCollection(() 
                	-> new TreeSet<>(Comparator.comparing(User::getUserId))), ArrayList::new));
发布了334 篇原创文章 · 获赞 186 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/u012060033/article/details/103683494