ArrayList remove vs removeAll

T_0*_*_01 6 java collections performance arraylist removeall

如果我想从arraylist中删除一个集合,最好使用什么?我认为ArrayList中的removeAll方法是为这个任务编写的,但是在我写的一个测试中,只是迭代遍历对象并删除它们个人的速度要快几秒.

你为此目的使用了什么?

编辑:

我在grepcode上找到的removeAll代码调用batchRemove(c,false):

private boolean更多... batchRemove(Collection c,boolean complement){

700         final Object[] elementData = this.elementData;
701         int r = 0, w = 0;
702         boolean modified = false;
703         try {
704             for (; r < size; r++)
705                 if (c.contains(elementData[r]) == complement)
706                     elementData[w++] = elementData[r];
707         } finally {
708             // Preserve behavioral compatibility with AbstractCollection,
709             // even if c.contains() throws.
710             if (r != size) {
711                 System.arraycopy(elementData, r,
712                                  elementData, w,
713                                  size - r);
714                 w += size - r;
715             }
716             if (w != size) {
717                 // clear to let GC do its work
718                 for (int i = w; i < size; i++)
719                     elementData[i] = null;
720                 modCount += size - w;
721                 size = w;
722                 modified = true;
723             }
724         }
725         return modified;
726     }
Run Code Online (Sandbox Code Playgroud)

我其实不明白..

我的测试代码是这样的:

public class RemoveVsRemovall {

    public static void main(String[] args){
        ArrayList<String> source = new ArrayList<>();
        ArrayList<String> toRemove = new ArrayList<>();
        for(int i = 0; i < 30000; i++){
            String s = String.valueOf(System.nanoTime());
            source.add(s);
            if(i % 2 == 0) toRemove.add(s);
        }
        long startTime = System.nanoTime();
        removeList1(source, toRemove);
        long endTime = System.nanoTime();
        System.out.println("diff: " + (endTime - startTime) * 1e-9);
    }

    static void removeList1(ArrayList<String> source, ArrayList<String> toRemove){
        source.removeAll(toRemove);
    }

    static void removeList2(ArrayList<String> source, ArrayList<String> toRemove){
        for(String s : toRemove){
            source.remove(s);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用不同的列表大小调用它几次并在两种方法之间切换.

Val*_*nck 4

很难对这个问题给出一般性答案有几个原因。

首先,您必须了解这些性能特征取决于实现。实现很可能会根据平台和 JDK 版本的不同而有所不同。

话虽如此,主要有两种实施策略removeAll

  1. 对于你的每个元素ArrayList,检查它是否在另一个元素中Collection;如果是这样,请将其删除。
  2. 对于 的每个元素Collection,检查它是否在ArrayList;中 如果是这样,请将其删除。

如果Collection执行包含在恒定时间内,则策略 1(渐近)获胜。另一方面,如果contains通过扫描整个连接来执行并且Collection迭代速度非常慢,则策略2通常具有优势,因为它只迭代Collection一次;但即使在这种情况下,如果Collection非常大,并且 的大部分元素都ArrayList在 的第一个元素之内Collection,那么策略 1 会再次获胜……就没有尽头。

您最好相信removeAll();的实现。如果失败,请尝试更改数据结构;如果这也失败了,请根据经验基准实施您自己的方法。