Java常用集合類
ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
讀寫效率
HashSet讀寫是最慢的,因為HashSet每次add要判斷hashcode,HashSet兩種循環中iterator 方式不穩定,不過總是比foreach要快一點。ArrayList讀寫效率其次,在ArrayList中間插入或刪除一個元素,要改變整個集合中該元素後面所有元素的下標位置。LinkedList讀寫速度最快,LinkedList的中間插入或刪除一個元素的開銷是固定的,只需要對插入位置前後的元素指針進行修改。
去除集合內部重復元素
如果要用HashSet對集合中元素實現去重,不推薦這種做法,因為hash算法的速度比遍歷一個ArrayList要慢得多。即使在ArrayList中進行兩次循環,所消耗的時間仍然快於直接使用HashSet的構造方法。
String stocks="001,002,003,002";
LinkedHashSet stocksSet=new LinkedHashSet<(Arrays.asList(stocks.split(",")));
return String.join(",",stocksSet);
ArrayList中的remove方法會將元素前移一個位置,這裏使用倒序刪除避免漏掉元素或者報並發錯誤。
String stocks="001,002,003,002";
ArrayList list=new ArrayList<>(Arrays.asList(stocks.split(",")));
for ( int i = 0 ; i < list.size() - 1 ; i ++ ) {
if (list.get(j).equals(list.get(i))) {
list.remove(j);
}
}
}
return String.join(",",list);
訪問元素
ArrayList的內部實現是基於基礎的對象數組的,因此,它使用get方法訪問列表中的任意一個元素時(random-access),它的速度要比LinkedList快。當然也包括使用 for(int i<0;i<list.size();i++) 這種循環方式。LinkedList中的get方法是按照順序從列表的一端開始檢查,直到另外一端。對LinkedList而言,利用Collections.reverse方法對列表進行順序反轉時,LinkedList性能要好些。
空間復雜度
ArrayList和LinkedList在空間復雜度上都具有一定的空間上的冗余。ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間,在LinkedList中有一個私有的內部類,定義如下:
private static class Entry {
Object element;
Entry next;
Entry previous;
}
每個Entry對象reference列表中的一個元素,同時還有在LinkedList中它的上一個元素和下一個元素。一個有1000個元素的LinkedList對象將有1000個鏈接在一起的Entry對象,每個對象都對應於列表中的一個元素。這樣的話,在一個LinkedList結構中將有一個很大的空間開銷,因為它要存儲這1000個Entity對象的相關信息。
ArrayList使用一個內置的數組來存儲元素,這個數組的起始容量是10.當數組需要增長時,新的容量按如下公式獲得:新容量=(舊容量*3)/2+1,也就是說每一次容量大概會增長50%。這就意味著,如果你有一個包含大量元素的ArrayList對象,那麽最終將有很大的空間會被浪費掉,這個浪費是由ArrayList的工作方式本身造成的。如果沒有足夠的空間來存放新的元素,數組將不得不被重新進行分配以便能夠增加新的元素。對數組進行重新分配,將會導致性能急劇下降。如果我們知道一個ArrayList將會有多少個元素,我們可以通過構造方法來指定容量。我們還可以通過trimToSize方法在ArrayList分配完畢之後去掉浪費掉的空間。
ArrayList和LinkedList循環遍歷方式的性能分析
1、for-each
List<String> testList = new ArrayList<String>();
for (String tmp : testList)
{
//use tmp;
}
2、叠代器方式這種遍歷方式是最常用的遍歷方式,因為書寫比較方便,而且不需要考慮數組越界的問題,Effective-Java中推薦使用此種寫法遍歷。
List<String> testList = new ArrayList<String>();
for (Iterator<String> iterator = testList.iterator(); iterator.hasNext();)
{
//String tmp = iterator.next();
}
3、下標遞增或遞減循環
List<String> testList = new ArrayList<String>();
for (int i = 0; i < testList.size(); i++;)
{
//String tmp = testList.get(i);
}
以上三種遍歷方式是在使用list時最常用的方式,那麽這三種方式在遍歷的速度已經性能上又有什麽區別呢?我們從數據的底層實現上來進行分析。下標遞增或者遞減循環是最早接觸到的遍歷方式,會經常出現數組越界的問題。
List底層儲存都是使用數組來進行存儲的,ArrayList是直接通過數組來進行存儲,而LinkedList則是使用數組模擬指針,來實現鏈表的方式,因此從這裏就可以總結出,ArrayList在使用下標的方式循環遍歷的時候性能最好,通過下標可以直接取數據,速度最快。而LinkedList因為有一層指針,無法直接取到對應的下標,因此在使用下標遍歷時就需要計算對應的下面是哪個元素,從指針的頭一步一步的走,所以效率就很低。想到指針就會聯想到叠代器,叠代器可以指向下一個元素,而叠代器就是使用指針來實現的,因此LinkedList在使用叠代器遍歷時會效率最高,叠代器直接通過LinkedList的指針進行遍歷,ArrayList在使用叠代器時,因為要通過ArrayList先生成指針,因此效率就會低於下標方式,而for-each又是在叠代器基礎上又進行了封裝,因此效率會更低一點,但是會很接近叠代器。
在進行list遍歷時,如果是對ArrayList進行遍歷,推薦使用下標方式,如果是LinkedList則推薦使用叠代器方式。
---------------------
作者:技術從業者
來源:CSDN
原文:https://blog.csdn.net/calvin4cn/article/details/84450978
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
Java常用集合類