• List获取差集产生的问题


    背景

    在批量保存数据的时候,需要和数据库进行比对。如果当前数据存在则从List集合中删除。

    List批量删除的话,一般都会考虑使用removeAll。

    操作流程如下:

    1、将现有批量数据的外部唯一字段和数据库中的数据进行匹配,返回现有存在的List对象

    2、使用removeAll功能,批量删除,取得当前差集。

    使用removeAll功能后,在批量保存的时候,还是直接导致了数据重复。

    Api 说明

    操作类型                  

    方法说明
    交集listA.retainAll(listB) 调用方法后ListA变为两个集合的交集,ListB不变
    差集listA.removeAll(listB) 调用方法后ListA变为两个集合的差集,ListB不变
    并集1.listA.removeAll(listB) 2.listA.addAll(listB)  去重,先取差集再并集。ListA变为两个集合的并集,ListB不变

    removeAll源码

     说啥都是虚的,翻removeAll源码牌子。

    1. public boolean removeAll(Collection c) {
    2. return batchRemove(c, false, 0, size);
    3. }
    4. ...
    5. boolean batchRemove(Collection c, boolean complement,
    6. final int from, final int end) {
    7. Objects.requireNonNull(c);
    8. final Object[] es = elementData;
    9. int r;
    10. // Optimize for initial run of survivors
    11. for (r = from;; r++) {
    12. if (r == end)
    13. return false;
    14. if (c.contains(es[r]) != complement)
    15. break;
    16. }
    17. int w = r++;
    18. try {
    19. for (Object e; r < end; r++)
    20. if (c.contains(e = es[r]) == complement)
    21. es[w++] = e;
    22. } catch (Throwable ex) {
    23. // Preserve behavioral compatibility with AbstractCollection,
    24. // even if c.contains() throws.
    25. System.arraycopy(es, r, es, w, end - r);
    26. w += end - r;
    27. throw ex;
    28. } finally {
    29. modCount += end - w;
    30. shiftTailOverGap(es, w, end);
    31. }
    32. return true;
    33. }

    我们可以看到,需要循环比较每个对象。

    1. for (r = from;; r++) {
    2. if (r == end)
    3. return false;
    4. if (c.contains(es[r]) != complement)
    5. break;
    6. }

    从数据库查出来的数据,包含了ID等其它字段。这样两个对象的属性就不一样了。所以会返回false。这样就达不到去重的目的了。

    自定义对象就可以使用下面JDK8+的Stream方式去去重了。

    将已经在库的数据(exitList)和需要保存的数据(entityList)匹配,将不存在库里的挑出来放到新的List(saveDataEntityList)中。

    伪代码如下:

    1. saveDataEntityList = entityList.stream().filter(f -> !exitList.stream().map(Entity::getId).collect(Collectors.toList()).contains(f.getId())
    2. ).collect(Collectors.toList());

    经过测试,发现OK,没有重复数据了。

    总结

    removeAll适合子集完全匹配和基础类型的操作,建议在自定义对象的时候,不要使用removeAll方法,而是使用stream的方式。

  • 相关阅读:
    python图像匹配:如何使用Python进行图像匹配
    windows下搭建mindspore的编译环境
    list
    js中replace函数的使用
    d合并json
    【算法训练-队列 一】【结构特性】用两个栈实现队列
    理性推广 | C1N短网址帮您节省运营成本!
    树形dp,LeetCode 2385. 感染二叉树需要的总时间
    给图片添加图片水印
    地方/园区产业规划之 “ 如何进行产业定位 ”
  • 原文地址:https://blog.csdn.net/m290345792/article/details/126030021