ArrayList 和 LinkedList 性能对比

547 阅读2分钟

集合分有序无序,也可分允许重复和不允许重复。

集合名称简介remark
ArrayList基于数组,查询快,增删慢,可重复,线程不安全,效率高插入元素时需要扩容,LinkedList不需要
LinkedList基于链表,查询慢,增删快,可重复,线程不安全,效率高不要循环获取LinkedList中的元素
HashSet无序,线程不安全,允许null值,元素不允许重复
TreeSet有序,线程不安全,不允许null值,元素不允许重复默认升序

List 继承了 Collection,ArrayList、LinkedList 实现了 List。

Set 继承了 Collection,HaseSet、TreeSet、LinkedHashSet 从 Set 中衍生而出。

ArrayList 与 LinkedList 性能对比

一味地说 ArrayList 的增删操作比 LinkedList 的增删快,是不对的。

/**
 * 代码运行环境:win10, JDK8, AMD R7 4800H
 */
public static void main(String[] args) {
        int count = 10000000;
        ArrayList<Integer> array = new ArrayList<>();
        LinkedList<Integer> linked = new LinkedList<>();

        long begin = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            array.add(i);
        }
        System.out.println("ArrayList add " + count + " num cost time : " + (System.currentTimeMillis() - begin));

        begin = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            linked.add(i);
        }
        System.out.println("LinkedList add " + count + " num cost time : " + (System.currentTimeMillis() - begin));
    }

运行代码,从控制台中可以看到两个列表添加10000000个参数的耗时:

ArrayList add 10000000 num cost time : 4255
LinkedList add 10000000 num cost time : 7929

相反,ArrayList 增删的效率比 LinkedList 的效率还要高。

如果是从头部插入,理论上 LinkedList 的效率比 ArrayList 高。LinkedList 提供 addFirst 方法,链表速度快。ArrayList 则还涉及到拷贝和扩容。

比较 LinkedList 和 ArrayList 的效率,需要结合数量以及增删的位置(头、尾、中间)来判断。

LinkedList 和 ArrayList 到底谁快可以参考:www.cnblogs.com/xiaofuge/p/…

HashSet 和 TreeSet

HashSet 如何做到集合中元素不重复?

HashSet 先获取对象的 HashCode,根据 HashCode 决定元素的存储位置。如果两个对象相等,即 ObjA.equals(ObjB),但 ObjA 和 ObjB 的 HashCode 不相等,也可以存放在同一个 HashSet 中。

/**
 * 构造对象,重写 equals 方法,制作两个对象相等但hashCode不相等的情况
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CommonBeanReWrite {
    private Integer integer;
    private Long aLong;

    @Override
    public boolean equals(Object obj) {
        CommonBeanReWrite commonBean = (CommonBeanReWrite) obj;
        return this.aLong.equals(commonBean.getALong());
    }
}

// 测试代码
private void testHashSetElementUnique() {
        HashSet<CommonBeanReWrite> hashSet = Sets.newHashSet();
        CommonBeanReWrite bean1 = CommonBeanReWrite.builder().integer(1).aLong(1L).build();
        CommonBeanReWrite bean2 = CommonBeanReWrite.builder().integer(2).aLong(1L).build();
        System.err.println("两个对象是否相等: " + bean1.equals(bean2));
        System.err.println("对象1的hashCode:" + bean1.hashCode());
        System.err.println("对象2的hashCode:" + bean2.hashCode());

        hashSet.add(bean1);
        hashSet.add(bean2);

        System.out.println("hashSet中元素的个数: " + hashSet.size());
    }

运行代码观察控制台输出结果

两个对象是否相等: true
hashSet中元素的个数: 2
对象1的hashCode:263025902
对象2的hashCode:438135304

两个对象相等(即A.equals(B)),但 HashCode 不相等,故可以共同存放在同一个 HashSet 中。

TreeSet 的排序

TreeSet 默认是升序,但是新建 TreeSet 时可以指定排序方式。

// 默认升序
private void testTreeSetDefaultSort() {
        TreeSet<Integer> treeSet = Sets.newTreeSet();
        treeSet.add(100);
        treeSet.add(50);
        treeSet.add(200);
        treeSet.add(150);
        treeSet.forEach(item -> System.out.print(item + "\t"));
    }

运行后控制台输出结果可以看出,TreeSet 默认的排序方式是升序

50	100	150	200

TreeSet 也可以设置自定义的排序规则、

// 设置降序
private void testTreeSetCustomizeSort() {
        TreeSet<Integer> treeSet = new TreeSet<>((o1, o2) -> {
            if(o1.equals(o2)){
                return 0;
            } else if (o1 > o2) {
                return -1;
            } else {
                return 1;
            }
        });
        treeSet.add(100);
        treeSet.add(50);
        treeSet.add(200);
        treeSet.add(150);
        treeSet.forEach(item -> System.out.print(item + "\t"));
    }

运行后通过控制台输出可以看出,TreeSet 按照自定义的排序方式进行存储

200	150	100	50