Java集合包含所有奇怪的行为

时间:2011-01-25 11:28:24

标签: java list collections hashset

我有以下代码,我在使用superList和subList,我想检查subList实际上是superList的subList。

我的对象没有实现hashCode或equals方法。我在测试中创建了类似的情况。当我运行测试时,结果显示JDK集合和常见集合的结果之间存在非常大的性能差异。运行测试后,我得到以下输出。

使用Java Collection API 8953 MilliSeconds&结果是真的 使用Commons Collection API 78 MilliSeconds&结果是真的

我的问题是为什么是java集合,处理containsAll操作的速度很慢。我在那里做错了吗?我无法控制集合类型我从遗留代码中获取它。我知道如果我使用HashSet作为superList,那么使用JDK containsAll操作我会获得很大的性能提升,但不幸的是,这对我来说是不可能的。

package com.mycompany.tests;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

import org.apache.commons.collections.CollectionUtils;
import org.junit.Before;
import org.junit.Test;

public class CollectionComparison_UnitTest {

    private Collection<MyClass> superList = new ArrayList<MyClass>();
    private Collection<MyClass> subList = new HashSet<MyClass>(50000);

    @Before
    public void setUp() throws Exception {

        for (int i = 0; i < 50000; i++) {
            MyClass myClass = new MyClass(i + "A String");
            superList.add(myClass);
        subList.add(myClass);
    }
}

@Test
public void testIt() {
    long startTime = System.currentTimeMillis();
    boolean isSubList = superList.containsAll(subList);
    System.out.println("Time Lapsed with Java Collection API "
            + (System.currentTimeMillis() - startTime)
            + " MilliSeconds & Result is " + isSubList);

    startTime = System.currentTimeMillis();
    isSubList = CollectionUtils.isSubCollection(subList, superList);
    System.out.println("Time Lapsed with Commons Collection API "
            + (System.currentTimeMillis() - startTime)
            + " MilliSeconds & Result is " + isSubList);
}

}

class MyClass {     String myString;

MyClass(String myString) {
    this.myString = myString;
}

String getMyString() {
    return myString;
}

}

3 个答案:

答案 0 :(得分:4)

不同的算法:

ArrayList.containsAll()提供 O(N * N),而CollectionUtils.isSubCollection()提供 O(N + N + N)

答案 1 :(得分:3)

您至少应该以相反的顺序尝试测试。您的结果可能只是表明JIT编译器正在完成其工作: - )

答案 2 :(得分:2)

ArrayList.containsAll继承自AbstractCollection.containsAll,是一个检查行中所有元素的简单循环。每个步骤都是慢速线性搜索。我不知道CollectionUtils是如何工作的,但是使用简单的循环并不难做得快。将第二个List转换为HashSet是一个肯定的胜利。对这两个列表进行排序并通过它们可能会更好。

编辑:

CollectionUtils source code表明了这一点。他们将这两个系列转换为“基数图”,这对于许多操作来说都是一种简单而通用的方式。在某些情况下,这可能不是一个好主意,例如,当第一个列表为空或非常短时,您实际上是在闲置时间。在你的情况下,与AbstractCollection.containsAll相比,这是一个巨大的胜利,但你可以做得更好。