1
Collection與Map
學習目標
• 認識Collection與Map架構
• 使用Collection與Map實作
• 對收集之物件進行排序
• 簡介Lambda表示式
• 簡介泛型語法
2
認識Collection架構
3
• 依需求使用不同的介面實作物件
4
• 只表示感興趣的介面或類別
5
具有索引的List
6
7
java.util.ArrayList
• 使用Object陣列來保存收集之物件
• 使用索引隨機存取時速度快
• 若需要調整索引順序時,會有較差的表現
• 陣列長度固定也是要考量的問題
• 有個可指定容量(Capacity)的建構式
8
LinkedList
9
10
11
12
• 每次add()物件時,才會建立新的Node來保
存物件,不會事先耗費記憶體
• 指定索引隨機存取物件時,會比較沒有效率
• 有利於調整索引順序
13
內容不重複的Set
14
• Set沒有將重複的學生資料排除
15
• 你沒有告訴Set,什麼樣的Student實例才
算是重複
• 以HashSet為例
16
17
• 許多場合要判斷物件是否重複時,都會呼叫
hashCode()與equals()方法
• 因此規格書中建議,兩個方法要同時實作
18
19
支援佇列操作的Queue
• 定義了offer()、poll()與peek()等方法
• 操作失敗時會傳回特定值
20
21
• Queue的子介面Deque
22
23
24
使用泛型
25
26
• 對API設計者造成一些語法上的麻煩,但對客
戶端會多一些友善
27
• Collection API支援泛型語法
• 沒有指定型態參數實際型態,程式碼中出現
型態參數的地方,就會回歸為使用Object
28
• 有一部份是編譯器蜜糖
29
• 以下會編譯錯誤:
30
• 有個介面宣告若是如下:
31
• 如果不指定T的實際型態,那麼T出現的位置
就回歸為使用Object
32
• JDK7以後有了點改善
• Java SE 10以後
33
• 也可以只在方法上定義泛型
• 若能將elemOf()設計為泛型方法
34
簡介Lambda表示式
• 匿名類別語法實作Request介面並建立實例
• 可以使用JDK8新增的Lambda表示式
35
• 如果有個介面宣告如下:
36
• 可以用泛型宣告的型態作為資訊來源
37
• 從JDK9開始
• Java SE 10
38
• 使用Lambda語法來實作
39
40
• 不鼓勵使用Lambda表示式來寫複雜的演算
• 不過若流程較為複雜,可以使用區塊{}符號
包括演算流程
41
Iterable與Iterator
• 寫個forEach()方法,可以顯示List收集
的物件
42
• 實作一個forEach()方法,可以顯示Queue
收集的物件
43
• iterator()方法在JDK5出現前,是定義在
Collection介面
• JDK5以後提昇至java.lang.Iterable
44
• 增強式for迴圈,運用在陣列、實作
Iterable介面的物件,
45
• 增強式for迴圈是編譯器蜜糖
46
• JDK8以後的版本,Iterable新增了
forEach()方法
47
Comparable與Comparator
48
49
• 將var改為List,雖然可以通過編譯,然而
執行時會拋出ClassCastException?
50
實作Comparable
51
• Integer實作了Comparable介面:
52
實作Comparator
• String本身有實作Comparable
53
• Collections的sort()方法有另一個重載
版本,可接受java.util.Comparator
54
• java.util.TreeSet
• java.util.PriorityQueue
55
• 可以使用Lambda語法讓它更簡潔一些:
• JDK8也在List增加了sort()方法
56
• 若有個List某些索引處包括null,現在打
算讓null排在最前頭,之後依字串長度由大
到小排序,那會怎麼寫?
57
58
• JDK8以後
59
常用Map實作類別
• 根據某鍵(Key)來取得對應的值(Value)
60
使用HashMap
61
使用TreeMap
• 鍵的部份會排序,條件是作為鍵的物件必須
實作Comparable介面
• 或是建構TreeMap時,指定實作
Comparator介面的物件
62
63
使用Properties
• 繼承HashTable,HashTable實作了Map
64
• 從檔案中讀取屬性
65
• 也可以使用loadFromXML()方法
66
• 使用java指令啟動JVM時,可以使用-D指
定系統屬性
67
68
走訪Map鍵值
69
70
71
淺談不可變特性
• 在純函數式語言中(像是Haskell),x = 1
• x就是1,1的名稱(而不是變數)就是x,不
會再是其他的東西
• 在Java中想使用變數來模仿不可變特性,通
常會把變數加上final修飾
72
副作用(Side effect)
• 具有副作用的方法會改變物件狀態
– Collections的sort()
– List本身的add()方法
• 程式語言本身有變數的概念,在撰寫時就容
易調整變數值,也就容易調整物件狀態,也
就易於變更整個系統狀態
73
• 副作用是個雙面刃
• 在一個設計不良的系統中,若沒有適當地控
管副作用,追蹤物件狀態會越來越困難
• 如果變數不可變,設計出來的方法就不會有
副作用,物件狀態也不可變
74
• 不可變物件(Immutable object)有許多好處
– 並行(Concurrent)程式設計時,不用擔心執行
緒共用競爭的問題
– 共用資料結構,達到節省時間及空間之目的
75
• Java畢竟不是以函數式為主要典範
• 看看Collection介面就知道了
– 有些方法操作都是選用的
– 若不打算提供實作的方法,可以丟出
UnsupportedOperationException
– 實作物件必須在文件上指明,支援哪些操作
76
• 有時在設計上,為了限制副作用的發生,會
希望某些物件具有不可變的特性
• 以便易於掌握物件狀態,從而易於掌握系統
某些部份的狀態
77
• 在JDK8以前,會透過Collections的
static方法:
– unmodifiableCollection()
– unmodifiableList()
– unmodifiableSet()
– unmodifiableMap()
• 取得一個無法修改的(unmodifiable)物件
• JDK9以後在List、Set、Map提供了of()
方法,用以建立不可變的List、Set或Map
實作物件
78
unmodifiableXXX()方法
79
• 傳回的物件只是無法修改(Unmodifiable)
,也就是僅僅不支援修改操作罷了
• 傳回的物件是不可修改,而非不可變動
80
List、Set、Map的of()方法
81
• 會建立不可變物件,不能對它們呼叫有副作
用的方法,否則會拋出
UnsupportedOperationException
82
83
• 不會參考至原elements參考之陣列
84
• 元素是淺層複製
85
• 如果想要更進一步的不可變特性,應該令
Student類別在定義時也支援不可變特性
86
• Arrays.asList()方法
87

CH09:Collection與Map