Collection(集合)、
List(列表-有序序列)、Set(集-無重複)、Queue(隊列-先進先出)
Vector(同步的ArrayList) Stack(先進後出) ArrayList(動態數組、高效隨機訪問) LinkedList(高效插入、刪除)
HashSet(HashMap實現) SortedSet(SortedMap實現)
ArrayDeque(循環數組實現的雙端隊列) PriorityQueue(小頂堆實現的優先隊列) LinkedList(鏈表實現的雙端隊列)
Map(映射,表)
Collection
iterater | size | add | remove | clear | contains | stream | removeIf |
splitIterater | isEmpty | addAll | removeAll | retainAll | containsAll | parallelStram | foreach |
add : 如果添加元素改變了集合,則返回true。如果集合沒有發生變化則返回false。
比如,添加時發現元素e已經存在,就不執行添加。
其它如:remove / removeIf / addAll 等返回值爲boolean的方法,返回值邏輯同上
Iterable / foreach
所有實現了Iterable接口的類的對象,都可以用foreach遍歷
Iterator<T> iterator()
void forEach(Consumer<? super T> action)
default Spliterator<T> spliterator()
Iterator
迭代器,所有實現了Iterable接口的類對象,都可獲得自己的迭代器,可以用來迭代訪問或者刪除所有元素。
remove / next / hasNext
當調用iterater.next()
時,指針指向下一位置的元素,並返回這個剛剛越過的元素。
調用iterater.remove()
時,會刪除掉剛越過的那個元素。如果調用remove之前沒有調用next是不合法的,必須越過並返回了要刪除的元素,才能對那個元素執行remove操作。
boolean hasNext()
E next()
default void remove()
default void forEachRemaining(Consumer<? super E> action)
ListIterator
針對List接口提供的迭代器
void add(E e); // 與Collection不同的是,此方法不返回boolean類型值,因爲List(有序序列)允許重複,所以會直接add,不做是否重複的檢查
// 另,此方法當前元素前添加元素,因此,如果剛獲得listIterator,沒有做任何next()操作,就調用add(e)的情況下,元素e是會添加到序列的頭部,而非尾部。
void set(E e); // 用e取代指針當前指向的元素
void remove(); //必須與next()或者previous()合用
boolean hasPrevious();
E previous();
int nextIndex(); // 返回後續調用next()時返回的元素的位置。
int previousIndex();
Queue
隊列:入隊add、出隊remove、報數element
Throws Exception : | add / remove / element |
return special value : | offer / poll / peek |
隊列,通常意義上指的是先進先出的隊列,add是指入隊到尾部,remove出隊則從頭部出,element(相當於get)也是訪問頭部數據。
也有一些特定要求的隊列,比如根據某種條件來決定每次出隊的元素。例如,要求每次出隊的都是當前隊列中最矮的那一個人,這種就是優先隊列(PriorityQueue)。
PriorityQueue
小頂堆實現的優先隊列 。能夠確保任意可讀的時刻,隊列的第一個元素一定是所有元素中最小的。
因爲是採用小頂堆實現的,因此隊列內的元素並非是邏輯有序的,隊列內的元素只是構成了一個小頂堆,能夠確保每次出隊時,返回的是最小元素。
用迭代器迭代訪問時,訪問得到的數據的順序是按照構成的小頂堆的元素順序。
- 入隊 add( E e) 時,會調整數據構成小頂堆
- 出隊 remove() 時,刪除堆頂元素root,再將剩餘元素調整成小頂堆,最後返回root。
- element()時,返回堆頂元素
Deque :雙端隊列,可代替堆棧
Throws exception : | addFirst / addLast | removeFirst / removeLast | getFirst / getLast |
return special value : | offerFirst / offerLast | pollFirst / pollLast | peekFirst / peekLast |
Deque是雙端隊列。入隊、出隊、訪問都是既可在隊頭、也可在隊尾。
- 先進先出:removeFirst,addLast 或者 addFirst , removeLast
- 先進後出:removeLast,addLast 或者 addFirst , removeFirst
循環數組:ArrayDeque
有界:有容量限制的雙端隊列
鏈表:LinkedList
元素數量沒有上限的雙端隊列
自然有序·隨機訪問:List
有序:是指遍歷時訪問元素的順序同添加元素時的順序是一致的。而非比較排序後的有序。
因爲每個元素添加時都有特定位置。
可以隨機訪問:因爲每個元素的位置都是特定的,因此可以進行特定位置的隨機訪問,如下:
add(int index, E e) / remove( int index ) / get( int index) …
適合隨機訪問-RandomAccess:雖然所有List的實現類都可以隨機訪問,但是實際上只有內部數據結構爲數組的類適合隨機訪問,jdk爲這些類提供了一個接口RadomAccess來標記它們。
void add(int i, E e);
void addAll(int i , Collection<? extends E> c);
E get(int i);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int i);
void remove(int i);
int indexOf(Object obj);
int lastIndexOf(Object obj);
快速隨機訪問:ArrayList
封裝了一個動態再分配的對象數組。
調用get( int inex)可以實現快速隨機訪問。
使用ListIterator高效地插入刪除:LinkedList
使用鏈表的唯一理由是儘可能的減少在列表中間插入或者刪除元素所付出的代價。
用迭代器對鏈表做插入刪除操作:如果根據需求,可以對鏈表用listIterator做 add( e) / remove() 操作,那麼這種插入刪除操作非常高效。
避免所有使用整數索引訪問鏈表元素的方法,包括get(int index) / add( int index, E e) / remove( int index) 等,因爲對鏈表進行隨機訪問的效率較低。
例如,下面這段代碼的效率極低:
for(int i = 0 ; i < linkedList.size() ; i++){
E e = linkedList.get(i);
do something with e;
}
每次get(i)都要從列表的頭部重新開始搜索。linkedList對象根本不做任何緩存位置信息的操作。
因此,應該改成用迭代器的方式,如果程序中需要用到索引,可以用ListIterator類的int nextIndex()
方法獲取。
如果需要對列表進行隨機訪問,就用數組或者ArrayList,而不要使用鏈表。
同步的對象數組:Vector
Vector類的所有方法都是同步的,在同步上會耗費大量時間。
無重複元素:Set
Set中不允許有重複元素。
一個應用場景:讀取某個文件中的所有單詞,然後輸出所有不重複的單詞的數量(不是每個單詞的出現次數)。
散列集:HashSet
無序:遍歷時訪問元素的順序,同add時添加元素的順序是不一致的。
Set的實現類HashSet和TreeSet都是無序的,但是LinkedHashSet則是有序的。
不重複:equals判斷是否已經存在重複元素
HashSet(int initialCapacity) ; // initialCapacity是桶數
散列表
數組+鏈表(桶)
計算散列碼(hashCode),餘除桶數,算得桶號,如果有散列衝突,則拉鍊。
性能優化-桶數:通常設置爲預計元素個數的75%~150%。
默認值16,因此當確定元素個數遠大於16時,應主動設置桶數。以防解決散列衝突,和再散列帶來的性能下降。
再散列(rehash):當 元素個數 >= 桶數*裝填因子(load factor) 時,會進行再散列。
將增加桶至原來的2倍,並將所有元素重新散列至新的桶中。
自動比較排序集:SortedSet
向SortedSet中添加元素時,會調用相應的Comparable接口方法(或Comparator接口方法)對元素做比較排序,根據比較排序的結果將元素放在合適的位置,使得SortedSet的遍歷順序是一個經過比較排序後的有序序列。
Comparator<? super E> comparator();
E first(); // 返回集中的最小元素(也就是第一個元素)
E last(); // 返回集中的最大元素(也就是最後一個元素)
NavigableSet:
E higher(E value); // 返回集合中大於value的最小元素,如果沒有則返回null
E lower(E value); // 返回集合中小於value的最大元素,如果沒有則返回null
E ceiling(E value); // 返回集合中大於等於value的最小元素,如果沒有則返回null
E floor(E value); // 返回集合中小於等於value的最大元素,如果沒有則返回null
E pollFirst(); // 返回並刪除集中的最小元素
E pollLast(); // 返回並刪除集中的最大元素
Iterator<E> descendingIterator(); //返回一個按遞減順序遍歷集中元素的迭代器
TreeSet
每次向TreeSet中添加元素(add)時,都會先經歷比較排序,然後將元素放在合適的位置,因此耗時要比HashSet長。
比較排序:因爲需要對元素做比較排序,因此要求元素是Comparable接口的實現類的對象,或者在構造方法中提供一個比較器。
如果添加的元素不符合上述兩種情況,則add方法會拋出一個RuntimeException:java.lang.ClassCastException。
不重複:TreeSet檢查是否重複是通過Comparable接口或者Comparator接口來實現判斷的,如果這兩個接口的比較方法返回的是0,則認爲元素重複,如果已經存在重複的元素,則add方法將不會對TreeSet做任何更新。這點與HashSet的判斷重複的方法不同。
儘管添加元素時需要經歷比較排序,TreeSet仍比用鏈表或數組逐個檢查重複元素快很多。
有序Set:LikedHashSet
內置了一個LinkedHashMap