本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
Java8 Stream 实现复杂集合对象的差集、并集、交集!
昨天群里一位网友想要获取两个 List 集合之间的差集、并集、交集!群里网友群策群力,很多有人给他百度搜索到了一个结果。demo 案例如下所示:
import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;
public class Test {
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("1");
list1.add("2");
list1.add("3");
list1.add("5");
list1.add("6");
List<String> list2 = new ArrayList<String>();
list2.add("2");
list2.add("3");
list2.add("7");
list2.add("8");
// 交集
List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(toList());
System.out.println("---交集 intersection---");
intersection.parallelStream().forEach(System.out :: println);
// 差集 (list1 - list2)
List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(toList());
System.out.println("---差集 reduce1 (list1 - list2)---");
reduce1.parallelStream().forEach(System.out :: println);
// 差集 (list2 - list1)
List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(toList());
System.out.println("---差集 reduce2 (list2 - list1)---");
reduce2.parallelStream().forEach(System.out :: println);
// 并集
List<String> listAll = list1.parallelStream().collect(toList());
List<String> listAll2 = list2.parallelStream().collect(toList());
listAll.addAll(listAll2);
System.out.println("---并集 listAll---");
listAll.parallelStream().forEachOrdered(System.out :: println);
// 去重并集
List<String> listAllDistinct = listAll.stream().distinct().collect(toList());
System.out.println("---得到去重并集 listAllDistinct---");
listAllDistinct.parallelStream().forEachOrdered(System.out :: println);
System.out.println("---原来的List1---");
list1.parallelStream().forEachOrdered(System.out :: println);
System.out.println("---原来的List2---");
list2.parallelStream().forEachOrdered(System.out :: println);
}
}
然后这位网友照着 demo 代码修改一番,发现不行。
虽然上面的 demo 运行是可以的,但是把 List 集合中的 String 变成对象后,实现不了功能。
于是他贴出了自己的代码,List<UserDTO>
替换了 List<String>
,其他保持不变。
UserDTO 的定义如下:
@Data
public class UserDTO{
private String id;
private String name;
private Integer age;
}
为什么 String 变成 UserDTO 后不行了呢?
原因是,List 的 contains 方法用的比较是 equals,UserDTO 没有自己重写 equals 方法,因此默认的 equals 比较的是继承 Object 类提供的 equals。Object 中 equals 方法比较的是两个引用的内存地址。因此,contains 后发现对象都不相等,全是差集。
那么现在的解决方法有两种,一种是让 UserDTO 类自己重写 equals 方法。
还有一种是先找出要比较的 id,或者 name,再取对象。
第一种过于简单,我就不说了,我主要说一说,第二种做法。
package com.stream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
*
* @ClassName: TwoListCopare
* @Description: 两个List<对象>取交集\并集\差集</>
**/
public class TwoListCopare {
public static void main(String[] args) {
UserDTO userOld1 = new UserDTO("1","aaa",22);
UserDTO userOld2 = new UserDTO("2","bbb",32);
UserDTO userOld3 = new UserDTO("3","ccc",11);
UserDTO userOld4 = new UserDTO("4","ddd",42);
UserDTO userOld5 = new UserDTO("5","bbb",22);
UserDTO userOld6 = new UserDTO("6","eee",24);
UserDTO userNew1 = new UserDTO("7","dada",22); //新增一个
UserDTO userNew2 = new UserDTO("2","bbb",32); //不变一个
UserDTO userNew3 = new UserDTO("3","kaka",33); //更新一个
UserDTO userNew4 = new UserDTO("8","dbdb",42); //新增一个
UserDTO userNew5 = new UserDTO("5","bbb",100); //更新一个
//当然,少了1,4,6
List<UserDTO> mapAdd = new ArrayList<>();
List<UserDTO> oldList = new ArrayList<>();
List<UserDTO> newList = new ArrayList<>();
//添加老数据
oldList.add(userOld1);
oldList.add(userOld2);
oldList.add(userOld3);
oldList.add(userOld4);
oldList.add(userOld5);
oldList.add(userOld6);
//添加新数据
newList.add(userNew1);
newList.add(userNew2);
newList.add(userNew3);
newList.add(userNew4);
newList.add(userNew5);
//去交集,既获取id相同的交集,需要更新
//1.先提取出id和结果,用map形式
List<String> oldIds = new ArrayList<>();
List<String> newIds = new ArrayList<>();
oldList.stream().forEach(it->oldIds.add(it.getId()));
newList.stream().forEach(it->newIds.add(it.getId()));
// oldIds.stream().forEach(System.out::println);
// newIds.stream().forEach(System.out::println);
//取交集id
System.out.println("-----------------交集----------------------");
List<String> collectUpdate = newIds.stream().filter(it -> oldIds.contains(it)).collect(Collectors.toList());
collectUpdate.stream().forEach(System.out::println);
//取对应交集的对象
System.out.println("------------------交集的对象---------------------");
List<UserDTO> userUpdate = newList.stream().filter(it -> collectUpdate.contains(it.getId())).collect(Collectors.toList());
userUpdate.stream().forEach(System.out::println);
//取old的差集
System.out.println("-----------------old的差集----------------------");
List<String> collectDelete = oldIds.stream().filter(it -> !newIds.contains(it)).collect(Collectors.toList());
collectDelete.stream().forEach((System.out::println));
//取对应old差集对象
System.out.println("-----------------old差集对象----------------------");
List<UserDTO> userDelete = oldList.stream().filter(it -> collectDelete.contains(it.getId())).collect(Collectors.toList());
userDelete.stream().forEach(System.out::println);
//取new的差集
System.out.println("-----------------new的差集----------------------");
List<String> collectAdd = newIds.stream().filter(it -> !oldIds.contains(it)).collect(Collectors.toList());
collectAdd.stream().forEach((System.out::println));
//取对应old差集对象
System.out.println("-------------------old差集对象--------------------");
List<UserDTO> userAdd = newList.stream().filter(it -> collectAdd.contains(it.getId())).collect(Collectors.toList());
userAdd.stream().forEach(System.out::println);
//取并集
System.out.println("-------------------并集--------------------");
List<String> allIds = new ArrayList<>();
//获取一个包含了oldIds和newIds的总结合,但是没有去重
allIds.addAll(oldIds);
allIds.addAll(newIds);
//去重,获取并集ids的新集合
List<String> joinIds = allIds.stream().distinct().collect(Collectors.toList());
joinIds.stream().forEach(System.out::println);
}
}
我这个 demo 中,我取的是 id,大家可以根据需要取不同的字段。或者组合字段,比如,id + name 的形式。
重写 equals 大家一定要注意,hashCode 也需要重写。
@Data
public class UserDTO{
private String id;
private String name;
private Integer age;
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;//地址相等
}
if(obj == null){
return false;//非空性:对于任意非空引用x,x.equals(null)应该返回false。
}
if(obj instanceof UserDTO){
UserDTO other = (UserDTO) obj;
//需要比较的字段相等,则这两个对象相等
if(equalsStr(this.name, other.name)
&& equalsStr(this.age, other.age)){
return true;
}
}
return false;
}
private boolean equalsStr(String str1, String str2){
if(StringUtils.isEmpty(str1) && StringUtils.isEmpty(str2)){
return true;
}
if(!StringUtils.isEmpty(str1) && str1.equals(str2)){
return true;
}
return false;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (name == null ? 0 : name.hashCode());
result = 31 * result + (age == null ? 0 : age.hashCode());
return result;
}
}
以上内容来自群友的智慧,这里分享出来,方便初学者总结知识!
最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » Java8 Stream 实现复杂集合对象的差集、并集、交集