探究下集合类指定初始容量的必要性

以ArrayList为例,对比下指定初始容量和不指定两种情况对List.add性能的影响

        /**
         * 指定初始容量后:耗时 1030
         */
        ArrayList<Object> list = new ArrayList<Object>();
        final int N = 10000000;
        list = new ArrayList<Object>(N);
        long startTime1 = System.currentTimeMillis();
        for (int i = 0; i < N; i++) {
            list.add(i);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("指定初始容量后:" + (endTime1 - startTime1));

    /**
         * 不指定容量:耗时 1432
         */
        ArrayList<Object> list = new ArrayList<Object>();
        final int N = 10000000;
        list = new ArrayList<Object>();
        long startTime1 = System.currentTimeMillis();
        for (int i = 0; i < N; i++) {
            list.add(i);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("不指定容量:" + (endTime1 - startTime1));

指定容量的List做add操作明显比不指定的快。

ensureCapacity方法

如果List的初始化不是自己掌握的,那么我们在add大量数据之前可以调用 list.ensureCapacity(N); 以减少增量重新分配的次数,提升List的add性能。

ArrayList.ensureCapacity 源码如下:

    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

下面进行ensureCapacity测试

        /**
         * 不使用 ensureCapacity耗时 1916
         */
        ArrayList<Object> list = new ArrayList<Object>();
        final int N = 10000000;
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < N; i++) {
            list.add(i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("不使用ensureCapacity:"+(endTime - startTime));

        /**
         * 使用 ensureCapacity 耗时 1089
         */
        ArrayList<Object> list = new ArrayList<Object>();
        final int N = 10000000;
        list = new ArrayList<Object>();
        long startTime1 = System.currentTimeMillis();
        list.ensureCapacity(N);
        for (int i = 0; i < N; i++) {
            list.add(i);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("使用ensureCapacity方法后:" + (endTime1 - startTime1));

答案显而易见

何况,阿里手册上也有相关信息:

【推荐】集合初始化时,指定集合初始值大小。
说明:HashMap 使用 HashMap(int initialCapacity) 初始化。
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认
为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。
反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被
迫扩大,resize 需要重建 hash 表,严重影响性能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章