第8章java 集合

第8章java 集合

java集合大致可以分爲 Set  List  Queue  Map 四類 其中 Set表示無序,不可重複的集合,List代表有序,重複集合 Map表示具有映射關係的集合 Queue 代表隊列集合實現方式

8.1集合概述

爲了保持數量不確定,以及保存具有映射關係的數據,java提供了集合類

數組元素既可以保存基本類型的數據,也可以保存對象 ,但是 集合就只能保存對象

 

java集合類主要是由2個接口派生出來的 Collection Map, 這2個接口是集合框架的根接口

 

8.2 CollectionIterater接口

Collection接口是 List Set Queue接口的父接口,

Collection實現類都是重寫了toString()方法

Collection的父接口是Iterater

 

Iterater並不是把集合元素本身傳給了迭代變量,而是集合元素的值傳給了迭代變量

只有通過Iteraterremove()方法刪除上一次next()方法返回的集合元素纔可以

Iterater迭代器採用的是快速失敗 機制 ,一旦迭代器過程中檢測到了集合已經被修改,通常是程序中的其他線程修改,都會引起一場 這樣可以避免共享資源而引發的問題

 

8.2.5 使用java 8新增的Predicate操作集合

java 8 Collection集合新增了一個removeIf(Predicate filter)方法,該方法將會批量刪除符合filter條件的所有元素 Pridicate是一個謂詞(相當於是一個條件)

 

8.2.6 使用java 8 新增的Stream 操作集合

java 8 新增了Stream IntStream LongStream DoubleStream等流式API 這些API代表支持多個串行和並行聚集操作的元素

獨立使用stream的步驟

1. 使用Stream 或者XxxStream builder()方法創建該Stream對於的Builder

2. 重複調用Builderadd()方法向該流中添加多個元素

3. 調用Builderbuild()方法向該流裏添加對應的Stream

4. 調用Stream的聚集方法  調用的聚集方法每次只能執行一行

 

Stream提供了大量的方法進行聚集操作,這些方法既是 中間的 也可以是末端的

中間方法 中間操作允許流保持打開狀態,並允許直接調用後續方法。

末端方法 末端方法是對流的最終操作 執行末端方法後該流將被消耗 且不再可用

有狀態的方法 這種方法會給流增加一些新的屬性  比如元素的唯一性

短路方法 短路方法可以儘早的接結束對流的操作

  

Stream提供的方法可以對所有的集合元素進行處理 這樣大大簡化了集合編程的代碼

 

8.3 Set 集合

8.3.1 HashSet

HashSet是按Hash算法來存儲的集合,因此具有很好的查找性能

HashSet 集合具有以下的幾個特點

1. 不能保證元素的排列順序

2. HashSet 不是同步的

3. 集合元素值可以爲空

 

HashSet集合中存入元素時,HashSet會調用hashCode()方法來得到該對象的hashCode值,然後根據該hashCode值決定該對象在HashSet中存儲的位置,通過有兩個元素通過 equals 方法比較返回值爲true 但他們hashCode碼不相同,HashSet依然會把他們存儲在不同的地方

因此HashSet判斷兩個元素是否相等的標準是通過對象equals()方法和hashCode()兩個方法判斷

 

如果需要重寫equals()方法時 也應該重寫hashCode()方法 規則是 如果返回的equals()方法判斷相關元素相同 ,那麼hashCode()方法也應該相同

 

如果equals()方法判斷爲相同 hashCode()值不同,那麼這兩個對象會被保存在不同的地方 從而使元素添加成功,但是就與Set集合的規則衝突了

 

如果equals()判斷爲false 但是hashCode()值相同,HashSet集合試圖想他嗎存在同一個位置,但是又不行,所以實際上回採用鏈式存儲 導致性能降低

 

重寫hashCode()方法

1.在程序運行中,同一個對象調用hashCode()方法的返回值應該相同

2.當兩個對象通過equals()方法判斷爲true時,hashCode()值應該相同

3.對象中用作equals()方法比較的實例變量,都應該用於計算hashCode

 

如果想HashSet集合中添加一個可變對象後,後面的程序修改了可變的對象,則可能導致這個集合出現相同的元素,從而導致無法準確訪問到該對象

 

8.3.2 LinkedHashSet

LinkedHashSet 集合也是根據hashCode值來決定元素存儲位置的,但它同時也使用鏈表維護次序,LinkedHashSet 將會按照元素的添加順序來訪問集合裏的元素

在迭代全部元素的時候性能較好

 

8.3.3 TreeSet

TreeSetSortSet 接口的實現類,TreeSet可以確保集合元素處於排序狀態

Comparator comparator() 如果TreeSet 採用了定製排序,則該方法返回定製所有使用的Comparator 如果TreeSet 採用自然排序則返回 null

TreeSet 採用的是紅黑樹數據結構來存儲集合元素的

 

TreeSet有兩種排序方式 自然排序和定製排序

1. 自然排序 會調用集合元素的compareT哦(Object obj)方法來比較元素之間的大小關係,然後將集合元素按升序排序 

0bj1.compareTo(obj2) 如果該方法返回0  表示兩個元素相等 如果返回 正整數 表示obj1 > obj2

 

如果試圖把一個對象添加到TreeSet時,則該對象的類必須實現Comparable接口,否則會拋出異常

TreeSet集合中添加元素時,只有第一個元素無需實現Comparable接口,後面的都添加的所有元素都不想實現Comparable接口 。但當試圖從TreeSet中取出元素時,依然會出異常

 

大部分類在實現CompareTo(object obj) 方法時,都需要將比較對象obj強制類型轉換成相同類型,只有兩個相同類才能比較大小

 

所有希望TreeSet集合能正常運行就必須加入相同類型的元素

 

對於TreeSet 集合判斷兩個對象是否相等的唯一標準就是 兩個對象通過compareTo()方法返回值 是否等於0 如果爲0 則新對象無法加入TreeSet集合中

 

TreeSet中添加可變對象後,這將導致它與其他的對象大小發生改變,但是TreeSet並不會改變它的大小 有可能會導致TreeSet中存儲的兩個對象通過compareTo(Object obj) 方法比較返回 0

 

2制定排序    

需要在創建TreeSet集合對象時,提供一個Comparable(函數式接口)對象與集合關聯 修改Comparable對象負責對集合元素的排序邏輯

 

8.3.4 EnumSet

EnumSet是一個專門爲枚舉設計的集合類,EnumSet中的所有元素必須是指定的枚舉類型,該枚舉類型在創建EunmSet時顯示或者隱式指定 EunmSet的集合順序由枚舉類內的順序來決定

 

EnumSet在內部以位向量的形式存儲,這種存儲形式非常緊湊,高效,因此EnumSet對象佔內存很小,運行效率很高, 尤其是進行批量操作

 

EnumSet集合類不運行加入的元素爲 null

EnumSet沒有提供構造器來創建該類的實例,只能通過類方法來創建EnumSet對象

 

當試圖添加 或者複製一個Collection集合來創建EnumSet集合是,必須保證 元素都是同一個枚舉類的枚舉值

8.3.5 Set集合的性能分析

 

HashSet 性能總是比TreeSet好 特別是在 添加 查詢 元素等操作 因爲 TreeSet 需要額外的紅黑色樹算法來維護元素的次序

 

HashSet 有一個子類 LinkedHashSet 對於普通的插入。刪除都要比HashSet要慢一些 但是遍歷LinkedHashSet更快

 

EnumSet 性能是最好的,但是它只能保存同一個枚舉值類的枚舉值作爲集合元素

 

HashSet  EnumSet  LinkedHashSet 都是線程不安全的

 

8.4 List 集合

List集合代表一個元素有序,可重複集合,list集合默認按元素的添加順序設置元素的索引

 

8.4.1 java 8 改進List接口和ListIterator

List判斷對象相等時通過equals()方法判斷的

 

程序試圖刪除一個集合元素,會一次與集合進行比較,如果該equals()方法以繆一個集合元素作爲參數時返回true ,所以每次都是刪除第一個元素

 

8.4.2 ArrayList Vector 實現類

ArrayList Vector都是基於數組實現,所以ArrayList Vector 類封裝了一個動態的,允許再次分配的Object[]數組

 

如果向ArrayList或者Vector中增加大量的元素時,可以使用ensureCapacity方法,一次性的增加,可以減少分配次數,從而提高性能

initialCapacity 默認的長度爲10

 

ArrayList 是線程不安全的  Vector 是線程安全的

 

Vector還提供了一個Stack子類,它用於模擬棧 ,與其他集合一樣,進棧和出棧都是Object,因此從棧中取出元素,必須要進行類型轉換

 

ArrayDeque 也是List的實現類,ArrayDeque也實現了Deque接口,因此可以用來作爲棧使用 (也是基於數組實現的,性能也很好)

 

8.4.3 固定長度的List

Arrays 類中提供了一個方法 asList(Object ...a)方法 該方法可以把一個數組或者指定個數的對象轉換成一個List集合 ,這個數組既不是ArrayList實現類 也不是Vector實現類,而是Arrays內部類ArrayList的實例

Arrays.ArrayList是一個固定長度的List集合,程序只能遍歷訪問該集和裏的元素

 

8.5 Queue 集合

Queue 用於模擬隊列這種數據結構,隊列通常指“先進先出”的容器,通常隊列不允許隨機訪問對列中的元素

Deque 代表了一個雙端對列,可以同時從兩端添加,刪除,因此也可以被當做隊列使用,也可以做到棧來使用。

JAVA Deque提供了ArrayDeque LinkDeque 兩個實現類

 

8.5.1 PriorityQueue 實現類

PriorityQueue是一個比較標準的隊列實現類,這是因爲PriorityQueue保存隊列元素順序並不是按照添加隊列的順利,而是按照隊列元素的大小進行重新排序

PriorityQueue 不允許插入null元素

PriorityQueue有兩種排序方式 自然排序 和制定排序

8.5.2 接口與ArrayDeque實現類

Deque 底層數組的長度是 16

當程序中需要使用棧這個數據結構時,推薦使用ArrayDeque 儘量避免使用stack 因此stack是一個古老的集合 ,性能較差

 

8.5.3 LinkedList 實現類

LinkedList類實現了List接口,也實現了Deque接口,可以被當做雙端隊列來使用,因此既可以被當做棧來使用,也可以當做隊列使用

8.5.4 各種線性表的性能分析

java提供的List就是一種線性表接口,而ArrayListLinkedList 又是線性表的兩種典型實現。Queue代表了隊列,Deque代表了雙端隊列(既可以作爲隊列使用,又可以作爲棧 使用)

 

LinkedList 不僅提供了List集合的功能, 還提供了雙端隊列,棧的功能

 

對於ArrayList 集合,應該使用隨機訪問方法來遍歷集合元素, 對於LinkedList集合則應該使用迭代器來遍歷集合

 

8.6 JAVA 8 增強MAP集合

8.6.2 java 8 改進HashMap Hashtable實現類

Hashtable不允許使用 null作爲key value

HashMap 可以使用null作爲 key value

HashMapHashtable是通過equals()方法比較返回true即可。

 

如果程序使用了可變的對象作爲HashMap  Hashtable key,並且程序中修改了key的可變對象,則可能使得程序無法準確的訪問MAP中的被修改過的key

 

8.6.3 LinkedHashMap 實現類

LinkedHashMap 是使用雙向鏈表來維護key-value對的次序,該鏈表負責維護Map的迭代順序,迭代順序與key-value對的插入順序一致。

 

 

LinkedHashMap可以避免HashMapkey-value對進行維護

LinkedHashMap 需要維護元素的插入順序,因此性能低於hashMap

8.6.4 使用Properties 讀寫屬性文件

Properties類時Hashtable類的子類,該對象在處理屬性文件時特別方便,Properties類可以吧Map對象和屬性關聯起來,從而可以把Map對象中的key-values對寫入屬性文件中。也可以把屬性文件中的 屬性名=屬性值 加載到Map對象中

 

8.6.5 SortedMap接口和TreeMap實現接口

TreeMap就是紅黑樹數據結構,每個key-value 對即作爲紅黑樹的一個節點,

 

TreeMap是根據節點排序TreeMap可以保證素有的key-value 處於有序狀態

 

8.6.7 IdentityHashMap 實現類

IdentityHashMap類中當且僅當兩個key嚴格相等(key1=key2)時,才認爲這兩個key相等

 

8.6.8 EnumMap實現類

EnumMap類時一個與枚舉類一起使用的Map實現類,EnumMap中的所有key都必須是單個的枚舉類的枚舉值。創建EnumMap時,必須顯示或者隱式的創建一個

EnumMap類的特點

1. EnumMap類在內部已數組形式保存,所以這種實現形式非常緊湊,高效

2. EnumMap根據key的自然順序(枚舉值在枚舉類中定義的順序)來維護key-value

3. EnumMap不允許使用null作爲key 但允許使用null作爲value

8.6.9 Map實現類的性能分析

TreeMap通常要比HashMapHashtable要慢(用紅黑樹來管理key-value

TreeMap 集合中的key-value值總是處於有序狀態,

一般場景 多考慮HashMap,因爲HashMap正式爲快速查詢設計的(底層採用數組來存儲key-value),假如程序需要一個總是排好的Map時,則可以考慮使用TreeMap

LinkedHashMapHashMap慢一定點,因爲它要維護鏈表來維護key-value的添加順序

EnumMap性能最好

8.7 HashSetHashMap的性能選項

hash表裏可以存儲的元素的位置被稱爲桶,每一個桶裏存儲一個元素時桶的性能最好,但hash表的狀態是open的 在hash發生衝突的時候,單桶裏可能存儲多個元素,這些元素會以鏈表的形式存儲,必須按順序搜索

 

負載因子 HashSet HashMap hashtable集合的默認的負載極限是0.75 ,超過會成倍的增長

 

8.8操作集合的工具類Collections

java提供了一個操作Set list map 集合的工具類Collection,該工具類裏提供了大量方法對集合元素進行排序

8.8.3同步控制

Collection類中提供了很多synchronizedXxx()方法,該方法可以將指定的集合包裝成線程同步的集合,從而可以解決多線程併發訪問集合的線程安全問題

8.9總結

8.9.1List集合的三種遍歷方式

1. 增強for

2. 普通forlist.size()

3. 迭代器 Itreator iter = new Itreator; while(iter.hasNext) { iter.next()}

8.8.2 Set集合遍歷

1. 增強for

2. 迭代器 Itreator iter = new Itreator; while(iter.hasNext) { iter.next()}

8.8.3 Map集合遍歷集合

for-each循環中使用entries來遍歷 

for (Map.Entry<Integer, Integer> entry : map.entrySet()) 

entry.getKey()+"--->"+entry.getValue());

 

for-each循環中遍歷keysvalues

for (Integer key : map.keySet()) 

使用Iterator遍歷

Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); 

while (entries.hasNext()) { 

 Map.Entry<Integer, Integer> entry = entries.next(); 

Set entrySet() 返回Map中包含的key-value 對所組成的Set集合,每個集合元素都是Map.Entry  Map的內部類  Map集合裏的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章