Java 集合類是一種特別有用的工具類,大致可分為Set、List、Queue、Map四種體系。
Set代表無序、不可重復(fù)的集合;
List代表有序、重復(fù)的集合;
Map代表具有映射關(guān)系的集合;
Queue代表隊(duì)列集合。
一、集合概述
Java5在java.util.concurrent包下提供了一些多線程支持的集合類。
集合里只能保存對象。
Java的集合類主要由兩個接口派生:Collection和Map。

上圖中
Deque還有一個實(shí)現(xiàn)類ArrayDeque,只是我沒有找到合適的圖。。

最常用的集合類有:HashSet、TreeSet、ArrayDeque、ArrayList、LinkedList、HashMap、TreeMap
二、Collection和Iterator接口
Collection接口里面定義了如下操作集合元素的方法:
- boolean add(Object o)
- boolean addAll(Collection c)
- void clear()
- boolean contains(Object o)
- boolean isEmpty()
- Iterator iterator()
- boolean remove(Object o)
- boolean removeAll(Collection c)
- boolean retainAll(Collection c)
- int size()
- Object[] toArray()
使用lambda表達(dá)式遍歷集合
Java8為Iterable接口新增了一個forEach(Consumer action)默認(rèn)方法,該方法所需參數(shù)的類型是一個函數(shù)式接口,Iterable接口是Collection接口的父接口,Collection集合可以使用這個接口。
books.forEach(obj -> System.out.println(obj));
使用Java8增強(qiáng)的Iterator遍歷集合元素
Iterator接口提供了4中方法:
- boolean hasNext()
- Object next()
- void remove()
- void forEachRemaining(Consumer action)
Iterator it = books.iterator();
while(it.hasNext){
String book = (String)it.next();
}
Iterator必須依附于Collection對象。
使用Lambda表達(dá)式遍歷Iterator
it.forEachRemaining(obj->System.out.println(obj));
使用foreach循環(huán)遍歷集合元素
使用Java8新增的predicate操作集合
Java8為Collection集合新增了一個removeIf(Predicate filter)方法,批量刪除符合filter的元素。
books.removeIf(obj->((String)obj).length()<10);
使用Java8新增的Stream操作集合
Java8新增了Stream,IntStream,LongStream,DoubleStream等流式API,這些API代表多個支持串行和并行聚集操作的元素。還有每個Stream提供了Builder,如Stream.Builder,IntStream.Builder,開發(fā)者可以通過這些Builder來創(chuàng)建對應(yīng)的流。
獨(dú)立使用Stream的步驟:
- 使用Stream的builder類方法創(chuàng)建Builder
- 重復(fù)調(diào)用Builder的add方法添加元素
- 調(diào)用Builder的build方法獲取對應(yīng)的流
- 調(diào)用Stream的聚集操作
Stream提供了大量的方法,有"中間方法"(生成另外一個流)和"末端方法"(對流的最終操作)。
常用的中間方法:
- filter(Pridicate predicate)
- mapToXxx(ToXxxFunction Mapper)
- peek(Consumer action)
- distict()
- sorted()
- limit(long maxSize)
常用的末端方法:
- forEache(Consumer action)
- toArray()
- reduce()
- min()
- max()
- count()
- anyMatch(Predicate predicate)
- allMatch(Predicate predicate)
- noneMatch(Predicate predicate)
- findFirst()
- findAny()
Java8為Collection提供了一個stream默認(rèn)方法。
三、Set集合
HashSet類
特點(diǎn):
- 不能保證順序
- 不能保證同步(多線程)
- 集合元素值可以是null
當(dāng)向HashSet集合添加一個元素時,HashSet會調(diào)用該對象的hashCode()方法得到對象的hashCode值,然后根據(jù)該hashCode值決定該對象在HashSet中的存儲位置。
HashSet集合判斷兩個元素相等的標(biāo)準(zhǔn)是兩個對象通過equals()方法比較相等,并且兩個對象的hashCode()方法返回值也想等。
重寫hashCode()方法的基本原則:
- 同一個對象多次調(diào)用應(yīng)該返回相等的值
- 當(dāng)兩個對象通過
equals()方法比較返回true時,他們的hashCode()值應(yīng)該相等 - 對象中用于
equals()比較的實(shí)例變量都應(yīng)該用于計(jì)算hashCode
重寫hashCode()的一般步驟:
- 把對象內(nèi)每個有意義的實(shí)例變量計(jì)算出一個int類型的hashCode值。
- 用第一步計(jì)算的多個hashCode值組合計(jì)算出一個hashCode值返回
hashCode值的計(jì)算方式:
| 變量類型 | 計(jì)算方式 |
|---|---|
| boolean | f?0:1 |
| 整數(shù)類型 | (int)f |
| long | (int)(f^(f>>>32)) |
| float | Float.floatToIntBits(f) |
| double | d = Double.doubleToLongBits(f);(int)(d^(d>>>32)) |
| 應(yīng)用類型 | f.hashCode() |
為了避免直接相加的偶然相等,可以通過為各實(shí)例變量的hashCode值乘以任意一個質(zhì)數(shù)后再相加。
LinkedHashSet
也是根據(jù)hashCode插入元素,但是要維護(hù)元素的插入順序,性能略低于HashSet。
TreeSet
TreeSet是SortedSet的實(shí)現(xiàn)類。有幾個額外方法:
- Comparator comparator()
- Object first()
- Object last()
- Object lower(Object e)
- Object hight(Object e)
- SortedSet subSet(Object fromElement, Object toELement)
- SortedSet headSet(Object toElement)
- SortedSet tailSet(Object toElement)
TreeSet使用紅黑樹的數(shù)據(jù)結(jié)構(gòu)來存儲集合元素。支持自然排序和定制排序。
自然排序
調(diào)用集合的compareTo(Object obj)方法比較元素之間的大小關(guān)系,然后按升序排序。
Comparable接口里定義了一個compareTo(Object obj)方法。
如果試圖把一個對象添加到TreSet,則該對象的類必須實(shí)現(xiàn)Comparable接口。
向TreeSet中插入元素時,第一個元素不會調(diào)用compareTo()方法
定制排序
創(chuàng)建TreeSet時傳遞給它一個Comparator對象即可,該接口是函數(shù)式接口,可以使用lambda表達(dá)式創(chuàng)建對象。
四、List集合
代表一個元素有序、可重復(fù)的集合,集合中每個元素都有其對應(yīng)的順序索引。
java8改進(jìn)的List接口和ListIterator接口
List接口的方法:
- void add(int index, Object element)
- boolean addAll(int index, Collection c)
- Object get(int index)
- int indexOf(Object o)
- int lastIndexOf(Object o)
- Object remove(int index)
- Object set(int index, Object element)
- List subList(int fromIndex, int toIndex)
- void replaceAll(UnaryOperator operator)
- void sort(Comparator c)
List判斷兩個對象相等只要通過equals方法返回true即可。
List除了有Set的iterator()方法之外,還有l(wèi)istIterator()方法,該方法返回一個ListIterator對象,ListIterator接口繼承于Iterator接口。ListIterator相較于Iterator多了如下方法:
- boolean hasPrevious()
- Object previous()
- void add(Object o)
ArrayList和Vector實(shí)現(xiàn)類
使用initialCapacity參數(shù)設(shè)置該數(shù)組的長度。如果需要向集合中添加大量元素,可使用ensureCapacity(int minCapacity)方法一次性地增加容量,可以減少重分配的次數(shù),提高性能。
可以在創(chuàng)建的時候指定initialCapacity,還可以通過一下兩個方式重新分配Object[]數(shù)組,不指定的話默認(rèn)長度為10:
- void ensureCapacity(int minCapacity)
- void trimToSize()
ArrayList和Vector用法幾乎完全相同,Vector是一個古老的集合,里面有重復(fù)的方法。
通常盡量少用Vector。
Vector是線程安全的,但效率低,ArrayList不是線程安全的,java.util.Collections類可以將ArrayList變成線程安全的。推薦使用ArrayList。
Stack是Vector的子類。有以下方法:
- Object peek()
- Object pop()
- void push(Object item)
Stack繼承于Vector,古老的類,線程安全,但是效率低,不建議使用??梢允褂煤髞淼?code>ArrayDeque類代替。
固定長度的List
Arrays類提供了asList(Object... a)方法,可以把一個數(shù)組或指定個數(shù)的對象轉(zhuǎn)換成List集合。這個List集合既不是ArrayList實(shí)現(xiàn)類的實(shí)例,也不是Vector實(shí)現(xiàn)類的實(shí)例,而是Arrays的內(nèi)部類ArrayList的實(shí)例。
Arrays.ArrayList是一個固定長度的List集合,只能遍歷,不可增加修改。
五、Queue集合
Queue接口中定義的方法:
- void add(Object e)
- Object element():獲取隊(duì)列頭元素,但不刪除
- boolean offer(Object e):加入元素,比add()好
- Object peek():獲取頭元素,如果為空,返回null
- Object poll():獲取頭元素,并刪除,如果為空,返回null
- Object remove():獲取頭元素,并刪除
Deque是Queue的子接口,代表雙端隊(duì)列。有ArrayDeque和LinkedList兩個實(shí)現(xiàn)類。
PriorityQueue實(shí)現(xiàn)類
內(nèi)部排序。
Deque接口和ArrayDeque實(shí)現(xiàn)類
Deque接口方法:
- void addFirst(Object e)
- void addLast(Object e)
- Iterator descendingIterator()
- Object getFirst()
- Object getLast()
- boolean offerFirst(Object e)
- boolean offerLast(Object e)
- Object peekFirst()
- Object peekLast()
- Object pollFirst()
- Object pollLast()
- Object pop()
- void push()
- Object removeFirst()
- Object removeFirstOccurrence(Object o)
- Object removeLast()
- Object removeLastOccurrence(Object o)
LinkedList實(shí)現(xiàn)類
LinkedList即可以當(dāng)成雙端隊(duì)列,也可以當(dāng)成棧使用,也可以當(dāng)成隊(duì)列使用。
ArrayList和ArrayDeque內(nèi)部使用數(shù)組實(shí)現(xiàn),而LinkedList內(nèi)部使用鏈表實(shí)現(xiàn)。
各種線性表的性能分析
整體來說ArrayList比LinkedList性能好。
- 如果需要遍歷List,對于ArrayList、Vector集合,應(yīng)該使用隨機(jī)訪問方法(get())遍歷;對于LinkedList則應(yīng)該采用Iterator遍歷。
- 經(jīng)常插入刪除,考慮使用LinkedList
- 多個線程,可以使用Collections將集合包裝成線程安全的集合。
六、Java8增強(qiáng)的Map集合
從Java源碼看,Java先實(shí)現(xiàn)了Map,然后通過包裝一個所有value都為null的Map就實(shí)現(xiàn)了Set集合。
Map的實(shí)現(xiàn)子類和子接口中key集的存儲形式和對應(yīng)Set集合中元素的存儲形式完全相同。
方法:
- void clear()
- boolean containsKey(Object key)
- boolean containsValue(Object value)
- Set entrySet()
返回Map中包含的key-value對所組成的Set集合,每個集合元素都是Map.Entry對象
- Object get(Object key)
- boolean isEmpty()
- Set keySet()
- Object put(Object key, Object value)
- void putAll(Map m)
- Object remove(Object key, Object value)
- int size()
- Collection values()
Map接口中有一個內(nèi)部類Entry,該類封裝了key-value鍵值對。Entry包含如下三個方法:
- Object getKey()
- Object getValue()
- Object setValue(V value)
java8新增的方法
- Object compute(Object key, BiFunction remappingFunction)
- Object computeIfAbsent(Object key, Function mappingFunction)
- Object computeIfPresent(Object key, BiFunction remappingFunction)
- void forEach(BiConsumer action)
- Object getOrDefault(Object key, V default Value)
- Object merge(Object key, Object value, BiFunction remappingFunction)
- Object putIfAbsent(Object key, Object value)
- Object replace(Object key, Object value)
- boolean replace(K key, V oldValue, V newValue)
- replaceA(BiFunction Function)
java8改進(jìn)的Hash Map和Hashtable實(shí)現(xiàn)類
hashtable和vector同一時期出現(xiàn)。
區(qū)別:
- Hashtable是線程安全的
- Hashtable不允許null作為key和value
用作key的對象必須實(shí)現(xiàn)hashcode()和equals()方法
與HashSet類似,盡量不要使用可變對象作為HashMap、Hashtable的key。
LinkedHashMap
使用雙向鏈表維護(hù)key-value對的次序。
使用Properties讀寫屬性文件
Properties是Hashtable的子類。
- String getProperty(String key)
- String getProperty(String key, String defaultValue)
- String setProperty(String key, String value)
- void load(InputStream inStream)
- void store(OutputStream out, String comments)
SortedMap接口和TreeMap實(shí)現(xiàn)類
Map性能分析
HashMap和Hashtable實(shí)現(xiàn)機(jī)制相同,但由于Hashtable是一個古老的、線程安全的集合,HashMap通常比Hashtable快。
TreeMap更慢,但是其key-value是有序狀態(tài),無需專門的排序操作??梢哉{(diào)用keySet(),再用toArray()方法,再用Arrays的binarySearch()方法快速查找對象。
七、操作集合的工具類Collections
排序
- void reverse(List list)
- void shuffle(List list)
- void sort(List list)
- void sort(List list, Comparator c)
- void swap(List list, int i, int j)
- void rotate(List list, int distance)
查找、替換操作
- int binarySearch(List list, Object key)
- Object Max(Collection coll)
- Object Max(Collection coll, Comparator c)
- Object Min(Collection coll)
- Object Min(Collection coll, Comparator c)
- void fill(List list, Object obj)
- int frequency(Collection c, Object o)
- int indexOfSubList(List source, List target)
- int lastIndexOfSubList(List source, List target)
- boolean replaceAll(List list, Object oldVal, Object newVal)
同步控制
synchronizaedXxx()方法。
設(shè)置不可變集合
- emptyXxx()
- singletonXxx()
- unmodifiableXxx()
九、繁瑣的接口Enumeration
該接口是Iterator接口的古老版本。
不要使用,使用Iterator代替