list.removeAll 会随着数量的增加,性能变得很差,原因为: list.contains 需要进行两次遍历
private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++) 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 for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified; }
public boolean contains(Object o) { return indexOf(o) >= 0; } /** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the lowest index <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
解法:使用HashSet 和LinkedList 进行替换(HashSet保证元素唯一性,LinkedList提升插入删除性能)
public List<T> removeAll(List<T> source, List<T> destination) { List<T> result = new LinkedList<T>(); Set<T> destinationSet = new HashSet<T>(destination); for(T t : source) { if (!destinationSet.contains(t)) { result.add(t); } } return result;
}
评述:主要是使用HashSet具有散列性质的contains 替换 需要进行两次遍历的contains
原文:https://www.cnblogs.com/wangsong412/p/12693751.html