這篇文章總結(jié)了所有的Java集合(Collection)。主要介紹各個(gè)集合的特性和用途,以及在不同的集合類(lèi)型之間轉(zhuǎn)換的方式。
Arrays
Array是Java特有的數(shù)組。在你知道所要處理數(shù)據(jù)元素個(gè)數(shù)的情況下非常好用。java.util.Arrays 包含了許多處理數(shù)據(jù)的實(shí)用方法:
- Arrays.asList:可以從
Array 轉(zhuǎn)換成 List 。可以作為其他集合類(lèi)型構(gòu)造器的參數(shù)。 - Arrays.binarySearch:在一個(gè)已排序的或者其中一段中快速查找。
- Arrays.copyOf:如果你想擴(kuò)大數(shù)組容量又不想改變它的內(nèi)容的時(shí)候可以使用這個(gè)方法。
- Arrays.copyOfRange:可以復(fù)制整個(gè)數(shù)組或其中的一部分。
- Arrays.deepEquals
、 Arrays.deepHashCode:Arrays.equals/hashCode 的高級(jí)版本,支持子數(shù)組的操作。 - Arrays.equals:如果你想要比較兩個(gè)數(shù)組是否相等,應(yīng)該調(diào)用這個(gè)方法而不是數(shù)組對(duì)象中的
equals 方法(數(shù)組對(duì)象中沒(méi)有重寫(xiě)equals() 方法,所以這個(gè)方法之比較引用而不比較內(nèi)容)。這個(gè)方法集合了Java 5的自動(dòng)裝箱和無(wú)參變量的特性,來(lái)實(shí)現(xiàn)將一個(gè)變量快速地傳給 equals() 方法——所以這個(gè)方法在比較了對(duì)象的類(lèi)型之后是直接傳值進(jìn)去比較的。 - Arrays.fill:用一個(gè)給定的值填充整個(gè)數(shù)組或其中的一部分。
- Arrays.hashCode:用來(lái)根據(jù)數(shù)組的內(nèi)容計(jì)算其哈希值(數(shù)組對(duì)象的
hashCode() 不可用)。這個(gè)方法集合了Java 5的自動(dòng)裝箱和無(wú)參變量的特性,來(lái)實(shí)現(xiàn)將一個(gè)變量快速地傳給 Arrays.hashcode 方法——只是傳值進(jìn)去,不是對(duì)象。 - Arrays.sort:對(duì)整個(gè)數(shù)組或者數(shù)組的一部分進(jìn)行排序。也可以使用此方法用給定的比較器對(duì)對(duì)象數(shù)組進(jìn)行排序。
- Arrays.toString:打印數(shù)組的內(nèi)容。
如果想要復(fù)制整個(gè)數(shù)組或其中一部分到另一個(gè)數(shù)組,可以調(diào)用 System.arraycopy 方法。此方法從源數(shù)組中指定的位置復(fù)制指定個(gè)數(shù)的元素到目標(biāo)數(shù)組里。這無(wú)疑是一個(gè)簡(jiǎn)便的方法。(有時(shí)候用 ByteBuffer bulk復(fù)制會(huì)更快??梢詤⒖?a href="http:///various-methods-of-binary-serialization-in-java/" rel="nofollow" target="_blank">這篇文章).
最后,所有的集合都可以用T[] Collection.toArray( T[] a ) 這個(gè)方法復(fù)制到數(shù)組中。通常會(huì)用這樣的方式調(diào)用:
1 | return coll.toArray( new T[ coll.size() ] );
|
這個(gè)方法會(huì)分配足夠大的數(shù)組來(lái)儲(chǔ)存所有的集合,這樣 toArray 在返回值時(shí)就不必再分配空間了。
單線(xiàn)程集合
這一部分介紹的是不支持多線(xiàn)程的集合。這些集合都在java.util 包里。其中一些在Java 1.o的時(shí)候就有了(現(xiàn)在已經(jīng)棄用),其中大多數(shù)在Java 1.4中重新發(fā)布。枚舉集合在Java 1.5中重新發(fā)布,并且從這個(gè)版本之后所有的集合都支持泛型。PriorityQueue 也在Java 1.5中加入。非線(xiàn)程安全的集合架構(gòu)的最后一個(gè)版本是ArrayDeque ,也在Java 1.6中重新發(fā)布了。
List
- ArrayList:最有用的
List 集合實(shí)現(xiàn)。由一個(gè)整形數(shù)字或數(shù)組存儲(chǔ)了集合的大?。〝?shù)組中第一個(gè)沒(méi)有使用的元素)。像所有的List 集合一樣,ArrayList 可以在必要的時(shí)候擴(kuò)展它的大小。ArrayList訪(fǎng)問(wèn)元素的時(shí)間開(kāi)銷(xiāo)固定。在尾部添加元素成本低(為常數(shù)復(fù)雜度),而在頭部添加元素成本很高(線(xiàn)性復(fù)雜度)。這是由ArrayList 的實(shí)現(xiàn)原理——所有的元素的從角標(biāo)為0開(kāi)始一個(gè)接著一個(gè)排列造成的。也就是說(shuō),從要插入的元素位置往后,每個(gè)元素都要向后移動(dòng)一個(gè)位置。CPU緩存友好的集合是基于數(shù)組的。(其實(shí)也不是很友好,因?yàn)橛袝r(shí)數(shù)組會(huì)包含對(duì)象,這樣存儲(chǔ)的只是指向?qū)嶋H對(duì)象的指針)。 - LinkedList:
Deque 實(shí)現(xiàn):每一個(gè)節(jié)點(diǎn)都保存著上一個(gè)節(jié)點(diǎn)和下一個(gè)節(jié)點(diǎn)的指針。這就意味著數(shù)據(jù)的存取和更新具有線(xiàn)性復(fù)雜度(這也是一個(gè)最佳化的實(shí)現(xiàn),每次操作都不會(huì)遍歷數(shù)組一半以上,操作成本最高的元素就是數(shù)組中間的那個(gè))。如果想寫(xiě)出高效的LinkedList 代碼可以使用 ListIterators 。如果你想用一個(gè)Queue/Deque 實(shí)現(xiàn)的話(huà)(你只需讀取第一個(gè)和最后一個(gè)元素就行了)——考慮用ArrayDeque 代替。 - Vector:一個(gè)帶有線(xiàn)程同步方法的
ArrayList 版本。現(xiàn)在直接用ArrayList 代替了。
Queues/deques
- ArrayDeque:
Deque 是基于有首尾指針的數(shù)組(環(huán)形緩沖區(qū))實(shí)現(xiàn)的。和LinkedList 不同,這個(gè)類(lèi)沒(méi)有實(shí)現(xiàn)List 接口。因此,如果沒(méi)有首尾元素的話(huà)就不能取出任何元素。這個(gè)類(lèi)比LinkedList 要好一些,因?yàn)樗a(chǎn)生的垃圾數(shù)量較少(在擴(kuò)展的時(shí)候舊的數(shù)組會(huì)被丟棄)。 - Stack:一種后進(jìn)先出的隊(duì)列。不要在生產(chǎn)代碼中使用,使用別的
Deque 來(lái)代替(ArrayDeque 比較好)。 - PriorityQueue:一個(gè)基于優(yōu)先級(jí)的隊(duì)列。使用自然順序或者制定的比較器來(lái)排序。他的主要屬性——
poll/peek/remove/element 會(huì)返回一個(gè)隊(duì)列的最小值。不僅如此,PriorityQueue 還實(shí)現(xiàn)了Iterable 接口,隊(duì)列迭代時(shí)不進(jìn)行排序(或者其他順序)。在需要排序的集合中,使用這個(gè)隊(duì)列會(huì)比TreeSet 等其他隊(duì)列要方便。
Maps
- HashMap:最常用的
Map 實(shí)現(xiàn)。只是將一個(gè)鍵和值相對(duì)應(yīng),并沒(méi)有其他的功能。對(duì)于復(fù)雜的hashCode method ,get/put 方法有固定的復(fù)雜度。 - EnumMap:枚舉類(lèi)型作為鍵值的
Map 。因?yàn)殒I的數(shù)量相對(duì)固定,所以在內(nèi)部用一個(gè)數(shù)組儲(chǔ)存對(duì)應(yīng)值。通常來(lái)說(shuō),效率要高于HashMap 。 - HashTable:舊
HashMap 的同步版本,新的代碼中也使用了HashMap 。 - IdentityHashMap:這是一個(gè)特殊的
Map 版本,它違背了一般Map 的規(guī)則:它使用 “==” 來(lái)比較引用而不是調(diào)用Object.equals 來(lái)判斷相等。這個(gè)特性使得此集合在遍歷圖表的算法中非常實(shí)用——可以方便地在IdentityHashMap 中存儲(chǔ)處理過(guò)的節(jié)點(diǎn)以及相關(guān)的數(shù)據(jù)。 - LinkedHashMap :
HashMap 和LinkedList 的結(jié)合,所有元素的插入順序存儲(chǔ)在LinkedList 中。這就是為什么迭代LinkedHashMap 的條目(entry)、鍵和值的時(shí)候總是遵循插入的順序。在JDK中,這是每元素消耗內(nèi)存最大的集合。 - TreeMap:一種基于已排序且?guī)?dǎo)向信息Map的紅黑樹(shù)。每次插入都會(huì)按照自然順序或者給定的比較器排序。這個(gè)
Map 需要實(shí)現(xiàn)equals 方法和Comparable/Comparator 。compareTo 需要前后一致。這個(gè)類(lèi)實(shí)現(xiàn)了一個(gè)NavigableMap 接口:可以帶有與鍵數(shù)量不同的入口,可以得到鍵的上一個(gè)或者下一個(gè)入口,可以得到另一Map 某一范圍的鍵(大致和SQL的BETWEEN 運(yùn)算符相同),以及其他的一些方法。 - WeakHashMap:這種
Map 通常用在數(shù)據(jù)緩存中。它將鍵存儲(chǔ)在WeakReference 中,就是說(shuō),如果沒(méi)有強(qiáng)引用指向鍵對(duì)象的話(huà),這些鍵就可以被垃圾回收線(xiàn)程回收。值被保存在強(qiáng)引用中。因此,你要確保沒(méi)有引用從值指向鍵或者將值也保存在弱引用中m.put(key, new WeakReference(value)) 。
Sets
- HashSet:一個(gè)基于
HashMap 的Set 實(shí)現(xiàn)。其中,所有的值為“假值”(同一個(gè)Object 對(duì)象具備和HashMap 同樣的性能。基于這個(gè)特性,這個(gè)數(shù)據(jù)結(jié)構(gòu)會(huì)消耗更多不必要的內(nèi)存。 - EnumSet:值為枚舉類(lèi)型的
Set 。Java的每一個(gè)enum 都映射成一個(gè)不同的int 。這就允許使用BitSet ——一個(gè)類(lèi)似的集合結(jié)構(gòu),其中每一比特都映射成不同的enum 。EnumSet 有兩種實(shí)現(xiàn),RegularEnumSet ——由一個(gè)單獨(dú)的long 存儲(chǔ)(能夠存儲(chǔ)64個(gè)枚舉值,99.9%的情況下是夠用的),JumboEnumSet ——由long[] 存儲(chǔ)。 - BitSet:一個(gè)比特Set。需要時(shí)??紤]用
BitSet 處理一組密集的整數(shù)Set (比如從一個(gè)預(yù)先知道的數(shù)字開(kāi)始的id集合)。這個(gè)類(lèi)用 long[] 來(lái)存儲(chǔ)bit 。 - LinkedHashMap:與
HashSet 一樣,這個(gè)類(lèi)基于LinkedHashMap 實(shí)現(xiàn)。這是唯一一個(gè)保持了插入順序的Set 。 - TreeSet:與
HashSet 類(lèi)似。這個(gè)類(lèi)是基于一個(gè)TreeMap 實(shí)例的。這是在單線(xiàn)程部分唯一一個(gè)排序的Set 。
java.util.Collections
就像有專(zhuān)門(mén)的java.util.Arrays 來(lái)處理數(shù)組,Java中對(duì)集合也有java.util.Collections 來(lái)處理。
第一組方法主要返回集合的各種數(shù)據(jù):
- Collections.checkedCollection / checkedList / checkedMap / checkedSet / checkedSortedMap / checkedSortedSet:檢查要添加的元素的類(lèi)型并返回結(jié)果。任何嘗試添加非法類(lèi)型的變量都會(huì)拋出一個(gè)
ClassCastException 異常。這個(gè)功能可以防止在運(yùn)行的時(shí)候出錯(cuò)。//fixme - Collections.emptyList / emptyMap / emptySet :返回一個(gè)固定的空集合,不能添加任何元素。
- Collections.singleton / singletonList / singletonMap:返回一個(gè)只有一個(gè)入口的 set/list/map 集合。
- Collections.synchronizedCollection / synchronizedList / synchronizedMap / synchronizedSet / synchronizedSortedMap / synchronizedSortedSet:獲得集合的線(xiàn)程安全版本(多線(xiàn)程操作時(shí)開(kāi)銷(xiāo)低但不高效,而且不支持類(lèi)似
put 或update 這樣的復(fù)合操作) - Collections.unmodifiableCollection / unmodifiableList / unmodifiableMap / unmodifiableSet / unmodifiableSortedMap / unmodifiableSortedSet:返回一個(gè)不可變的集合。當(dāng)一個(gè)不可變對(duì)象中包含集合的時(shí)候,可以使用此方法。
第二組方法中,其中有一些方法因?yàn)槟承┰驔](méi)有加入到集合中:
- Collections.addAll:添加一些元素或者一個(gè)數(shù)組的內(nèi)容到集合中。
- Collections.binarySearch:和數(shù)組的
Arrays.binarySearch 功能相同。 - Collections.disjoint:檢查兩個(gè)集合是不是沒(méi)有相同的元素。
- Collections.fill:用一個(gè)指定的值代替集合中的所有元素。
- Collections.frequency:集合中有多少元素是和給定元素相同的。
- Collections.indexOfSubList / lastIndexOfSubList:和
String.indexOf(String) / lastIndexOf(String) 方法類(lèi)似——找出給定的List 中第一個(gè)出現(xiàn)或者最后一個(gè)出現(xiàn)的子表。 - Collections.max / min:找出基于自然順序或者比較器排序的集合中,最大的或者最小的元素。
- Collections.replaceAll:將集合中的某一元素替換成另一個(gè)元素。
- Collections.reverse:顛倒排列元素在集合中的順序。如果你要在排序之后使用這個(gè)方法的話(huà),在列表排序時(shí),最好使用
Collections.reverseOrder 比較器。 - Collections.rotate:根據(jù)給定的距離旋轉(zhuǎn)元素。
- Collections.shuffle:隨機(jī)排放
List 集合中的節(jié)點(diǎn),可以給定你自己的生成器——例如 java.util.Random / java.util.ThreadLocalRandom or java.security.SecureRandom 。 - Collections.sort:將集合按照自然順序或者給定的順序排序。
- Collections.swap:交換集合中兩個(gè)元素的位置(多數(shù)開(kāi)發(fā)者都是自己實(shí)現(xiàn)這個(gè)操作的)。
并發(fā)集合
這一部分將介紹java.util.concurrent 包中線(xiàn)程安全的集合。這些集合的主要屬性是一個(gè)不可分割的必須執(zhí)行的方法。因?yàn)椴l(fā)的操作,例如add 或update 或者check 再update ,都有一次以上的調(diào)用,必須同步。因?yàn)榈谝徊綇募现薪M合操作查詢(xún)到的信息在開(kāi)始第二步操作時(shí)可能變?yōu)闊o(wú)效數(shù)據(jù)。
多數(shù)的并發(fā)集合是在Java 1.5引入的。ConcurrentSkipListMap / ConcurrentSkipListSet 和 LinkedBlockingDeque 是在Java 1.6新加入的。Java 1.7加入了最后的 ConcurrentLinkedDeque 和 LinkedTransferQueue
Lists
- CopyOnWriteArrayList:list的實(shí)現(xiàn)每一次更新都會(huì)產(chǎn)生一個(gè)新的隱含數(shù)組副本,所以這個(gè)操作成本很高。通常用在遍歷操作比更新操作多的集合,比如
listeners/observers 集合。
Queues/deques
- ArrayBlockingQueue:基于數(shù)組實(shí)現(xiàn)的一個(gè)有界阻塞隊(duì),大小不能重新定義。所以當(dāng)你試圖向一個(gè)滿(mǎn)的隊(duì)列添加元素的時(shí)候,就會(huì)受到阻塞,直到另一個(gè)方法從隊(duì)列中取出元素。
- ConcurrentLinkedDeque / ConcurrentLinkedQueue:基于鏈表實(shí)現(xiàn)的無(wú)界隊(duì)列,添加元素不會(huì)堵塞。但是這就要求這個(gè)集合的消費(fèi)者工作速度至少要和生產(chǎn)這一樣快,不然內(nèi)存就會(huì)耗盡。嚴(yán)重依賴(lài)于CAS(compare-and-set)操作。
- DelayQueue:無(wú)界的保存
Delayed 元素的集合。元素只有在延時(shí)已經(jīng)過(guò)期的時(shí)候才能被取出。隊(duì)列的第一個(gè)元素延期最?。ò?fù)值——延時(shí)已經(jīng)過(guò)期)。當(dāng)你要實(shí)現(xiàn)一個(gè)延期任務(wù)的隊(duì)列的時(shí)候使用(不要自己手動(dòng)實(shí)現(xiàn)——使用ScheduledThreadPoolExecutor )。 - LinkedBlockingDeque / LinkedBlockingQueue:可選擇有界或者無(wú)界基于鏈表的實(shí)現(xiàn)。在隊(duì)列為空或者滿(mǎn)的情況下使用
ReentrantLock-s 。 - LinkedTransferQueue:基于鏈表的無(wú)界隊(duì)列。除了通常的隊(duì)列操作,它還有一系列的
transfer 方法,可以讓生產(chǎn)者直接給等待的消費(fèi)者傳遞信息,這樣就不用將元素存儲(chǔ)到隊(duì)列中了。這是一個(gè)基于CAS操作的無(wú)鎖集合。 - PriorityBlockingQueue:
PriorityQueue 的無(wú)界的版本。 - SynchronousQueue:一個(gè)有界隊(duì)列,其中沒(méi)有任何內(nèi)存容量。這就意味著任何插入操作必須等到響應(yīng)的取出操作才能執(zhí)行,反之亦反。如果不需要
Queue 接口的話(huà),通過(guò)Exchanger 類(lèi)也能完成響應(yīng)的功能。
Maps
- ConcurrentHashMap:
get 操作全并發(fā)訪(fǎng)問(wèn),put 操作可配置并發(fā)操作的哈希表。并發(fā)的級(jí)別可以通過(guò)構(gòu)造函數(shù)中concurrencyLevel 參數(shù)設(shè)置(默認(rèn)級(jí)別16)。該參數(shù)會(huì)在Map 內(nèi)部劃分一些分區(qū)。在put 操作的時(shí)候只有只有更新的分區(qū)是鎖住的。這種Map 不是代替HashMap 的線(xiàn)程安全版本——任何 get-then-put 的操作都需要在外部進(jìn)行同步。 - ConcurrentSkipListMap:基于跳躍列表(Skip List)的
ConcurrentNavigableMap 實(shí)現(xiàn)。本質(zhì)上這種集合可以當(dāng)做一種TreeMap 的線(xiàn)程安全版本來(lái)使用。
Sets
- ConcurrentSkipListSet:使用
ConcurrentSkipListMap 來(lái)存儲(chǔ)的線(xiàn)程安全的Set 。 - CopyOnWriteArraySet:使用
CopyOnWriteArrayList 來(lái)存儲(chǔ)的線(xiàn)程安全的Set 。
相關(guān)閱讀
推薦閱讀
如果想要了解更多關(guān)于Java集合的知識(shí),推薦閱讀以下書(shū)籍:
總結(jié)
|
單線(xiàn)程 |
并發(fā) |
Lists |
ArrayList ——基于泛型數(shù)組LinkedList ——不推薦使用Vector ——已廢棄(deprecated)
|
CopyOnWriteArrayList ——幾乎不更新,常用來(lái)遍歷
|
Queues / deques |
ArrayDeque ——基于泛型數(shù)組Stack ——已廢棄(deprecated)PriorityQueue ——讀取操作的內(nèi)容已排序
|
ArrayBlockingQueue ——帶邊界的阻塞式隊(duì)列ConcurrentLinkedDeque / ConcurrentLinkedQueue ——無(wú)邊界的鏈表隊(duì)列(CAS)DelayQueue ——元素帶有延遲的隊(duì)列LinkedBlockingDeque / LinkedBlockingQueue ——鏈表隊(duì)列(帶鎖),可設(shè)定是否帶邊界LinkedTransferQueue ——可將元素`transfer`進(jìn)行w/o存儲(chǔ)PriorityBlockingQueue ——并發(fā)PriorityQueue SynchronousQueue ——使用Queue 接口進(jìn)行Exchanger
|
Maps |
HashMap ——通用MapEnumMap ——鍵使用enum Hashtable ——已廢棄(deprecated)IdentityHashMap ——鍵使用== 進(jìn)行比較LinkedHashMap ——保持插入順序TreeMap ——鍵已排序WeakHashMap ——適用于緩存(cache)
|
ConcurrentHashMap ——通用并發(fā)MapConcurrentSkipListMap ——已排序的并發(fā)Map
|
Sets |
HashSet ——通用setEnumSet ——enum SetBitSet ——比特或密集的整數(shù)SetLinkedHashSet ——保持插入順序TreeSet ——排序Set
|
ConcurrentSkipListSet ——排序并發(fā)SetCopyOnWriteArraySet ——幾乎不更新,通常只做遍歷
|
|