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

以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 表,嚴重影響性能。

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