两个对应不同类的list如果有相同的id,差集去重
2017-02-05 14:43
316 查看
今天上班,review同事写的代码,发现了一个bug,这里就不贴出实际代码了,自己写段代码,来重现一下这个bug。(别纠结代码,我是用groovy写的,有的人说你的java代码为什么没有分号,汗)。
其实,目的就是两个对应不同类但是有相同字段的list进行去重复的操作。
有两个类A,B
class A {
Long id
String detail
Long getId() {
return id
}
void setId(Long id) {
this.id = id
}
String getDetail() {
return detail
}
void setDetail(String detail) {
this.detail = detail
}
}
这两个类有着相同的id字段。
现在假设的场景如下:
有三个用户A,内容分别是这样的
A a1 = new A()
a1.setId(1)
a1.setDetail("a1detail")
A a2 = new A()
a2.setId(2)
a2.setDetail("a2detail")
A a3 = new A()
a3.setId(3)
a3.setDetail("a3detail")
有两个用户B,内容分别是这样的
B b1 = new B()
b1.setId(1)
B b2 = new B()
b2.setId(2)
B b3 = new B()
分别存储到两个不同ArrayList<A> as 和 ArrayList<B> bs 中,最终想得到的内容是as中去掉id与bs中相同的用户,也就是上面情景中最终只剩下 a3用户。
这个同事写的代码是这样的:
//new 两个新的list,将不同的结果存储到这两个list中
ArrayList<A> returna = new ArrayList<>();
ArrayList<B> returnb = new ArrayList<>();
for (A a : aArrayList){
for (B b : bArrayList){
if (a.getId().equals(b.getId())){
returnb.add(b)
break
}else {
returna.add(a)
}
}
}
上面的代码中,else之后的语句是有问题,每次循环都有可能在遍历的时候,将之前存储过的对象a再次存储,从而出现重复。
正确的实现方式如下:
for (B b: bArrayList){
for (A a: aArrayList){
if(b.getId().equals(a.getId())){
bReturn.add(b)
aArrayList.remove(a)
break
}
}
}
因为bArrayList的集合是aArrayList集合的子集,所以最开始只是为了减少几次操作(不减少on方算法复杂度),才将bArrayList放在了最外层的循环中。
出于好奇,尝试把aArrayList放在外层循环,会发现报错的问题,报错如下:
Java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
后来发现,如果遍历ArrayList的时候,ArrayList增加或者删除了对象,就会报以上的错误,所以恰巧第一次写的代码正好在遍历aArrayList的时候,修改了aArrayList之后,break了当前的for循环。
报错参考下面的文章:
http://blog.csdn.net/lipei1220/article/details/9028669
其实,目的就是两个对应不同类但是有相同字段的list进行去重复的操作。
有两个类A,B
class A {
Long id
String detail
Long getId() {
return id
}
void setId(Long id) {
this.id = id
}
String getDetail() {
return detail
}
void setDetail(String detail) {
this.detail = detail
}
}
class B { Long id Long getId() { return id } void setId(Long id) { this.id = id } }
这两个类有着相同的id字段。
现在假设的场景如下:
有三个用户A,内容分别是这样的
A a1 = new A()
a1.setId(1)
a1.setDetail("a1detail")
A a2 = new A()
a2.setId(2)
a2.setDetail("a2detail")
A a3 = new A()
a3.setId(3)
a3.setDetail("a3detail")
有两个用户B,内容分别是这样的
B b1 = new B()
b1.setId(1)
B b2 = new B()
b2.setId(2)
B b3 = new B()
分别存储到两个不同ArrayList<A> as 和 ArrayList<B> bs 中,最终想得到的内容是as中去掉id与bs中相同的用户,也就是上面情景中最终只剩下 a3用户。
这个同事写的代码是这样的:
//new 两个新的list,将不同的结果存储到这两个list中
ArrayList<A> returna = new ArrayList<>();
ArrayList<B> returnb = new ArrayList<>();
for (A a : aArrayList){
for (B b : bArrayList){
if (a.getId().equals(b.getId())){
returnb.add(b)
break
}else {
returna.add(a)
}
}
}
上面的代码中,else之后的语句是有问题,每次循环都有可能在遍历的时候,将之前存储过的对象a再次存储,从而出现重复。
正确的实现方式如下:
for (B b: bArrayList){
for (A a: aArrayList){
if(b.getId().equals(a.getId())){
bReturn.add(b)
aArrayList.remove(a)
break
}
}
}
因为bArrayList的集合是aArrayList集合的子集,所以最开始只是为了减少几次操作(不减少on方算法复杂度),才将bArrayList放在了最外层的循环中。
出于好奇,尝试把aArrayList放在外层循环,会发现报错的问题,报错如下:
Java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
后来发现,如果遍历ArrayList的时候,ArrayList增加或者删除了对象,就会报以上的错误,所以恰巧第一次写的代码正好在遍历aArrayList的时候,修改了aArrayList之后,break了当前的for循环。
报错参考下面的文章:
http://blog.csdn.net/lipei1220/article/details/9028669
相关文章推荐
- 比较两个List元素是否相同,查找出两个list的不同元素
- go判断两个字符串是否是是相互打乱的,也就是说它们有着相同的字符,但 是对应不同的顺序。
- 使用saveOrUpdate方法时,若hibernate的session存在了两个具有相同id的不同实体,则会报错
- 如果在一个SQL语句中有两个来自不同表的字段,有相同的字段名怎么办?
- php 比较获取两个数组相同和不同元素(交集和差集)
- 编写一个函数,判断两个字符串是否是是相互打乱的,也就是说它们有着相同的字符,但是对应不同的顺序。
- VBA,两个sheet根据第一列id相同比较其余列,不同的值放到sheet3中
- 找出list中的不同元素、删除两个list中相同的对象
- 多数据情况下 高效性的 找到两个List中的相同,不同等数据信息
- 两个不同的list 有相同的 主键 快速 融合
- php获取两个数组相同的元素(交集)以及比较两个数组中不同的元素(差集)
- Java相同类型的两个对象比较属性值,得到不同属性的名称和对应的值,附代码实例
- 关于两个List如何快速高效去除相同的元素,保留不同的元素
- 求助 android开发中 如果两个控件的id相同 会怎样?如何使用findviewbyid ()寻找到?
- 找出list中的不同元素、删除两个list中相同的对象
- [转]Android试验:如果View的ID相同会出现什么效果?
- 同步两个数据库相同名字的ID
- 两个有序整形数组找出二者相同的元素和不同的元素
- Q : 请问若欲在同时间使用两个以上相同的设备,而该设备的厂商ID与设备ID皆相同,WinDriver 驱动程序开发工具是否亦可支持?
- HIBERNATE两个相同的标识符挂不同对象的解决