两个对应不同类的list如果有相同的id,差集去重

    xiaoxiao2021-03-26  21

    今天上班,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

    转载请注明原文地址: https://ju.6miu.com/read-660406.html

    最新回复(0)