集合是我們?cè)?Java 編程中使用非常廣泛的,它就像大海,海納百川,像萬能容器,盛裝萬物,而且這個(gè)大海,萬能容器還可以無限變大(如果條件允許)。當(dāng)這個(gè)海、容器的量變得非常大的時(shí)候,它的初始容量就會(huì)顯得很重要了,因?yàn)橥诤?、擴(kuò)容是需要消耗大量的人力物力財(cái)力的。同樣的道理,Collection 的初始容量也顯得異常重要。所以:對(duì)于已知的情景,請(qǐng)為集合指定初始容量。
public static void main(String[] args) {
StudentVO student = null;
long begin1 = System.currentTimeMillis();
List<StudentVO> list1 = new ArrayList<>();
for(int i = 0 ; i < 1000000; i++){
student = new StudentVO(i,"chenssy_"+i,i);
list1.add(student);
}
long end1 = System.currentTimeMillis();
System.out.println("list1 time:" + (end1 - begin1));
long begin2 = System.currentTimeMillis();
List<StudentVO> list2 = new ArrayList<>(1000000);
for(int i = 0 ; i < 1000000; i++){
student = new StudentVO(i,"chenssy_"+i,i);
list2.add(student);
}
long end2 = System.currentTimeMillis();
System.out.println("list2 time:" + (end2 - begin2));
}
上面代碼兩個(gè) list 都是插入 1000000 條數(shù)據(jù),只不過 list1 沒有沒有申請(qǐng)初始化容量,而 list2 初始化容量 1000000。那運(yùn)行結(jié)果如下:
list1 time:1638
list2 time:921
從上面的運(yùn)行結(jié)果我們可以看出 list2 的速度是 list1 的兩倍左右。在前面 LZ 就提過,ArrayList 的擴(kuò)容機(jī)制是比較消耗資源的。我們先看 ArrayList 的 add 方法:
public boolean add(E e) {
ensureCapacity(size + 1);
elementData[size++] = e;
return true;
}
public void ensureCapacity(int minCapacity) {
modCount++; //修改計(jì)數(shù)器
int oldCapacity = elementData.length;
//當(dāng)前需要的長(zhǎng)度超過了數(shù)組長(zhǎng)度,進(jìn)行擴(kuò)容處理
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
//新的容量 = 舊容量 * 1.5 + 1
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
//數(shù)組拷貝,生成新的數(shù)組
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
ArrayList 每次新增一個(gè)元素,就會(huì)檢測(cè) ArrayList 的當(dāng)前容量是否已經(jīng)到達(dá)臨界點(diǎn),如果到達(dá)臨界點(diǎn)則會(huì)擴(kuò)容 1.5 倍。然而 ArrayList 的擴(kuò)容以及數(shù)組的拷貝生成新的數(shù)組是相當(dāng)耗資源的。所以若我們事先已知集合的使用場(chǎng)景,知道集合的大概范圍,我們最好是指定初始化容量,這樣對(duì)資源的利用會(huì)更加好,尤其是大數(shù)據(jù)量的前提下,效率的提升和資源的利用會(huì)顯得更加具有優(yōu)勢(shì)。
Java 集合細(xì)節(jié)一:請(qǐng)為集合指定初始容量