-
总结
- 交集:两个list集合共同元素部分,retainAll()方法。
- 差集:从A集合中获取B集合中,没有的元素。removeAll()方法。
- 并集:将两个list集合并在一起,addAll()方法,但有可能出现重复元素,可以先removeAll(),去掉重复元素部分,再addAll()方法。
-
代码演示:
-
交集:retainAll()方法
package com.example.demo.list; import lombok.*; import java.util.ArrayList; import java.util.List; public class demo { public static void main(String[] args) { List<Person> list = new ArrayList<>(); list.add(new Person("小明","18")); list.add(new Person("中明","28")); list.add(new Person("大明","38")); list.add(new Person("老明","48")); List<Person> list2 = new ArrayList<>(); list2.add(new Person("小明","18")); list2.add(new Person("老明","48")); list2.add(new Person("老大明","58")); list2.add(new Person("老老明","68")); // 交集:共同元素部分 list.retainAll(list2); System.out.println(list); } @Data @NoArgsConstructor @AllArgsConstructor static class Person{ private String name; private String age; } }
-
差集:removeAll()方法
package com.example.demo.list; import lombok.*; import java.util.ArrayList; import java.util.List; public class demo { public static void main(String[] args) { List<Person> list = new ArrayList<>(); list.add(new Person("小明","18")); list.add(new Person("中明","28")); list.add(new Person("大明","38")); list.add(new Person("老明","48")); List<Person> list2 = new ArrayList<>(); list2.add(new Person("小明","18")); list2.add(new Person("老明","48")); list2.add(new Person("老大明","58")); list2.add(new Person("老老明","68")); // 差集:从A集合中获取B集合中,没有的元素 list.removeAll(list2); System.out.println(list); } @Data @NoArgsConstructor @AllArgsConstructor static class Person{ private String name; private String age; } }
-
并集:removeAll(),去掉重复元素部分,再addAll()方法。
package com.example.demo.list; import lombok.*; import java.util.ArrayList; import java.util.List; public class demo { public static void main(String[] args) { List<Person> list = new ArrayList<>(); list.add(new Person("小明","18")); list.add(new Person("中明","28")); list.add(new Person("大明","38")); list.add(new Person("老明","48")); List<Person> list2 = new ArrayList<>(); list2.add(new Person("小明","18")); list2.add(new Person("老明","48")); list2.add(new Person("老大明","58")); list2.add(new Person("老老明","68")); // 并集 list.removeAll(list2); System.out.println("先获取list集合中不存在list2集合的元素:"); System.out.println(list); list.addAll(list2); System.out.println("再将list2集合直接加到list集合中,达到去重的并集"); System.out.println(list); } @Data @NoArgsConstructor @AllArgsConstructor static class Person{ private String name; private String age; } }
-
-
源码原理
-
交集(retainAll())
public boolean retainAll(Collection<?> c) { // 先判断是否为null Objects.requireNonNull(c); // 调用批量移动方法 return batchRemove(c, true); }
-
差集(removeAll())
public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false); }
-
通过查看上面两个源码,发现都是调用了同一个batchRemove方法,只是最后传递的boolean不一样。
-
batchRemove()方法:
private boolean batchRemove(Collection<?> c, boolean complement) { // 设现是 集合ListA.retainAll(ListB) 则complement为true // 先把ListA的元素赋给elementData变量 final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { // 核心部分 size 是 ListA集合元素的个数 for (; r < size; r++) // 通过对 ListA的元素进行遍历 // 判断ListA的元素是否在ListB元素中,得到的结果再跟comlement进行比较 // 上述已设调用方法:集合ListA.retainAll(ListB) 则complement为true // 则 如果ListB元素包含ListA元素的话,则会返回true == complement,走到分支 if (c.contains(elementData[r]) == complement) // 这是典型的在原数组上进行操作的手法,减少内存开销,具体看下文的图片 elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { // clear to let GC do its work // 将其他赋予null 为了更好的GC for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified; }
-
addAll()方法:
public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); int cSize = c.size(); if (cSize==0) return false; checkForComodification(); // 核心 parent.addAll(parentOffset + index, c); this.modCount = parent.modCount; this.size += cSize; return true; }
public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); boolean modified = false; // 就是很普通的遍历,一个个add for (E e : c) { add(index++, e); modified = true; } return modified; }
-