您的位置:首页 > 其它

两个对应不同类的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
}
}
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ArrayList去重
相关文章推荐