基于ArrayList初始化長度的作用及影響
時(shí)間:2023-06-24 15:39:25
目錄
一、有無初始容量的區(qū)別二、initialCapacity != list.size()總結(jié)平時(shí)寫代碼都直接寫
Listlist = new ArrayList<>();
由于公司做政.府項(xiàng)目,對(duì)并發(fā)和響應(yīng)沒有太苛刻的要求,平時(shí)就沒有考慮到這一塊。
【資料圖】
今天看同事代碼在new ArrayList<>()的時(shí)候帶入初始容量,于是好奇百度一下,講結(jié)果記錄下來。
一、有無初始容量的區(qū)別
/**
? ? ?* The maximum size of array to allocate.
? ? ?* Some VMs reserve some header words in an array.
? ? ?* Attempts to allocate larger arrays may result in
? ? ?* OutOfMemoryError: Requested array size exceeds VM limit
? ? ?*/
? ? private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
? ??
?? ?/**
? ? ?* Default initial capacity.
? ? ?*/
? ? private static final int DEFAULT_CAPACITY = 10;
?? ?/**
? ? ?* The array buffer into which the elements of the ArrayList are stored.
? ? ?* The capacity of the ArrayList is the length of this array buffer. Any
? ? ?* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
? ? ?* will be expanded to DEFAULT_CAPACITY when the first element is added.
? ? ?*/
? ? transient Object[] elementData; // non-private to simplify nested class access
?? ?/**
? ? ?* Shared empty array instance used for empty instances.
? ? ?*/
? ? private static final Object[] EMPTY_ELEMENTDATA = {};?? ?
?? ?/**
? ? ?* Constructs an empty list with the specified initial capacity.
? ? ?*
? ? ?* @param ?initialCapacity ?the initial capacity of the list
? ? ?* @throws IllegalArgumentException if the specified initial capacity
? ? ?* ? ? ? ? is negative
? ? ?*/
? ? public ArrayList(int initialCapacity) {
? ? ? ? if (initialCapacity > 0) {
? ? ? ? ? ? this.elementData = new Object[initialCapacity];
? ? ? ? } else if (initialCapacity == 0) {
? ? ? ? ? ? this.elementData = EMPTY_ELEMENTDATA;
? ? ? ? } else {
? ? ? ? ? ? throw new IllegalArgumentException("Illegal Capacity: "+
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?initialCapacity);
? ? ? ? }
? ? }
?? ?/**
? ? ?* Increases the capacity to ensure that it can hold at least the
? ? ?* number of elements specified by the minimum capacity argument.
? ? ?*
? ? ?* @param minCapacity the desired minimum capacity
? ? ?*/
? ? private void grow(int minCapacity) {
? ? ? ? // overflow-conscious code
? ? ? ? int oldCapacity = elementData.length;
? ? ? ? int newCapacity = oldCapacity + (oldCapacity >> 1);
? ? ? ? if (newCapacity - minCapacity < 0)
? ? ? ? ? ? newCapacity = minCapacity;
? ? ? ? if (newCapacity - MAX_ARRAY_SIZE > 0)
? ? ? ? ? ? newCapacity = hugeCapacity(minCapacity);
? ? ? ? // minCapacity is usually close to size, so this is a win:
? ? ? ? elementData = Arrays.copyOf(elementData, newCapacity);
? ? }以上是JDK1.8的ArrayList源碼,可以看出,
沒有初始容量的話,在做數(shù)據(jù)操作的時(shí)候ArrayList會(huì)自己創(chuàng)建容量,JDK1.8默認(rèn)為10每次擴(kuò)容后容量為oldCapacity + (oldCapacity >> 1)容量最大值Integer.MAX_VALUE - 8由此可以想到,如果存在上千上萬數(shù)據(jù)量的操作,不初始容量和初始化了合適的容量,處理時(shí)間肯定不同,因?yàn)槌跏蓟蛿U(kuò)容是需要時(shí)間的。
測(cè)試代碼如下:
public static void main(String[] args) {
? ? final int count = 200 * 10000;
? ? List list = new ArrayList<>();
? ? long begin = System.currentTimeMillis();
? ? for(int i = 0; i < count ; i++) {
? ? ? ? list.add(i);
? ? }
? ? System.out.println("沒有設(shè)置ArrayList初始容量: " + (System.currentTimeMillis() - begin) + " ms");
? ? List list2 = new ArrayList<>(10);
? ? long begin2 = System.currentTimeMillis();
? ? for(int i = 0; i < count ; i++) {
? ? ? ? list2.add(i);
? ? }
? ? System.out.println("設(shè)置了ArrayList初始容量: " + (System.currentTimeMillis() - begin2) + " ms");
} 輸出:
沒有設(shè)置ArrayList初始容量: 96 ms
設(shè)置了ArrayList初始容量: 26 ms
分析:
在list.add()方法執(zhí)行時(shí),先調(diào)用ArrayList的:
/**
?* Appends the specified element to the end of this list.
?*
?* @param e element to be appended to this list
?* @return true (as specified by {@link Collection#add})
?*/
public boolean add(E e) {
? ? ensureCapacityInternal(size + 1); ?// Increments modCount!!
? ? elementData[size++] = e;
? ? return true;
}進(jìn)入方法:
private void ensureCapacityInternal(int minCapacity) {
? ? ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
再往下:
private static int calculateCapacity(Object[] elementData, int minCapacity) {
? ? if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {// 第一次add的時(shí)候,都會(huì)走這一步
? ? ? ? return Math.max(DEFAULT_CAPACITY, minCapacity);//初始化容量小于默認(rèn)值10都會(huì)取10,反之取自定義的容量
? ? }
? ? return minCapacity;
}擴(kuò)容方法:
private void ensureExplicitCapacity(int minCapacity) {
? ? modCount++;
? ? // overflow-conscious code
? ? if (minCapacity - elementData.length > 0)
? ? ? ? grow(minCapacity);
}
grow():
/**
?* Increases the capacity to ensure that it can hold at least the
?* number of elements specified by the minimum capacity argument.
?*
?* @param minCapacity the desired minimum capacity
?*/
?private void grow(int minCapacity) {//minCapacity是當(dāng)前容量,比如,默認(rèn)容量下,add一次后就是10+1
? ? // overflow-conscious code
? ? int oldCapacity = elementData.length;
? ? int newCapacity = oldCapacity + (oldCapacity >> 1);
? ? if (newCapacity - minCapacity < 0)
? ? ? ? newCapacity = minCapacity;
? ? if (newCapacity - MAX_ARRAY_SIZE > 0)
? ? ? ? newCapacity = hugeCapacity(minCapacity);
? ? // minCapacity is usually close to size, so this is a win:
? ? elementData = Arrays.copyOf(elementData, newCapacity);
}總結(jié):
建議初始化容量,減少系統(tǒng)初始化容量的耗時(shí);初始化容量不是越大越好,跟系統(tǒng)配置相關(guān),因?yàn)橐_辟內(nèi)存。如果能確定add的總數(shù),以總數(shù)作為初始容量效率最高,但這種場(chǎng)景太少了。最佳的設(shè)置要兼顧內(nèi)存空間和擴(kuò)容次數(shù),我也沒有找到最優(yōu)解,歡迎大佬補(bǔ)充。盡管不知道初始化多少最快,但是初始化比未初始化快,并且有限的數(shù)據(jù)量下,設(shè)置不同initialCapacity的差距不大。最終,我建議大家初始化容量,并且就寫10(<=10都一樣,看自己喜好)。上例不同大小初始容量的耗時(shí):
| initialCapacity | time |
|---|---|
| 未初始化 | 96 |
| <=10 | 26 |
| 100 | 26 |
| 1000 | 23 |
| 10000 | 648 |
| 100000 | 24 |
| 1000000 | 18 |
| 10000000 | 609 |
二、initialCapacity != list.size()
public static void main(String[] args) {
? ? List list = new ArrayList<>(10);
? ? list.set(0, 666);
} console:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.set(ArrayList.java:448)
at top.chengsw.demo.test.ListTest.main(ListTest.java:25)
此時(shí),list.size() = 0。
也就是說,該構(gòu)造方法并不是將ArrayList()初始化為指定長度,而是指定了其內(nèi)部的Object數(shù)組的長度,也就是其容量。
當(dāng)我們調(diào)用size()時(shí),返回的是其實(shí)際長度,而非容量大小。
對(duì)超出ArrayList長度的部分進(jìn)行訪問或賦值操作時(shí)也會(huì)造成訪問越界,盡管它的容量大小足夠。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)稿件
瓦格納創(chuàng)始人被控“號(hào)召叛亂”,莫斯科啟動(dòng)反恐,普京將發(fā)表講話
當(dāng)前熱訊:恐拒絕留守,76人慌了!不給大合同,你們會(huì)為自己行為付出代價(jià)
每日訊息!這兩個(gè)人都來玩《晶核》了?我愿稱之為3D版DNF!
苯乙烯商品報(bào)價(jià)動(dòng)態(tài)(2023-06-24)|環(huán)球訊息
2023年6月24日硫化鈉價(jià)格最新行情預(yù)測(cè)_觀點(diǎn)
俄羅斯總統(tǒng)普京發(fā)表電視講話|焦點(diǎn)快看
天津和平區(qū)總工會(huì)舉行2023年度快遞行業(yè)集體合同簽約儀式|焦點(diǎn)觀察
2023河北經(jīng)貿(mào)大學(xué)招生計(jì)劃-各專業(yè)招生人數(shù)是多少
打磨拋光設(shè)備全套_打磨拋光設(shè)備|環(huán)球微動(dòng)態(tài)
做不了主播的薇婭、雪梨,干了同一件事:蓋樓 今日看點(diǎn)
日本2萬億豪賭太陽能新技術(shù),能趕超中國嗎? 世界通訊
世界觀點(diǎn):環(huán)球視點(diǎn)!手持四五十萬預(yù)算 GLC長軸距8款車型怎么選
焦點(diǎn)快報(bào)!外資企業(yè)看好中國 持續(xù)增資擴(kuò)產(chǎn)
扶老挈幼觀舟去 飛槳逐浪劈波來——《藝術(shù)里的奧林匹克》帶您共賞《觀競(jìng)渡》中的民族體育盛會(huì)|世界播報(bào)
消暑熱 清心煩 試試這兩款養(yǎng)生茶 世界時(shí)快訊
當(dāng)前熱議!中德“隱形冠軍”企業(yè)齊聚,這場(chǎng)合作交流會(huì)聚焦智能制造發(fā)展
讓傳統(tǒng)節(jié)日綻放時(shí)代新韻(今日談)
“留學(xué)生被綁架”索要500萬贖金 武漢民警76小時(shí)營救_環(huán)球最新
當(dāng)前通訊!阿那亞戲劇節(jié)丨導(dǎo)演孟京輝:“勾起人們交流的意愿最重要”
這個(gè)新增市場(chǎng),或達(dá)百億美元! 環(huán)球快看點(diǎn)
【環(huán)球速看料】中國媒體行業(yè):AI應(yīng)用催化不斷 把握游戲主線 關(guān)注C端應(yīng)用邏輯兌現(xiàn)
騰訊湯道生:大模型只是起點(diǎn),產(chǎn)業(yè)落地是AI更大的應(yīng)用場(chǎng)景
教育頻道
6月25號(hào)開始財(cái)運(yùn)開花,大吉大利,3生肖正財(cái)運(yùn)攀升 世界看熱訊
【熱聞】普里戈任大談“對(duì)抗俄軍” 俄將領(lǐng)急忙喊話
天天觀天下!用心靈守候你 祝勇_關(guān)于用心靈守候你 祝勇介紹
全球今亮點(diǎn)!【駕春秋】2025款大眾探歌諜照曝光 將是最后一代燃油版
歷史上入侵我國的匈奴,如今是哪個(gè)民族你知道嗎-環(huán)球觀點(diǎn)
【全球獨(dú)家】廈門地鐵6號(hào)線角美延伸段角社盾構(gòu)區(qū)間實(shí)現(xiàn)雙線貫通
特利迦9月11號(hào)正式播出,等待了兩個(gè)月終于要來了!
自購原料按照網(wǎng)上配方勾兌,男子造出多款名牌洗衣液|即時(shí)焦點(diǎn)
環(huán)球播報(bào):成都市應(yīng)急管理局: 6月23日至8月中旬 全面排查整治城鎮(zhèn)燃?xì)忸I(lǐng)域安全隱患問題


