Java 8 Map新增的一些method可以取代我們以前在操作map時多餘的code,使用到對應的
method及Lambda語法可以使冗長的判斷程式碼縮短至一行就可以了!
在此將提到的是
這些方法所對應到的行為,裡面的實作已包含我們平常會用到的判斷式!
而官方的API說明還特別列出相關的pseudo code來解說這些method
若您需要使用到的話可以先從這裡來了解!
PS. 在帶入相關的參數中,還可能會利用到Lambda語法! 請先了解一下這個部分囉!
這裡會從一個範例承上啟下的逐步說明下去,講解到這些method被使用到的話,會間接造
成什麼樣的結果,以此就可以判斷哪些method該用到實際應用的什麼地方上!
#putIfAbsent - 初始化map時可使用,所有key皆會被走訪
若key → value == null 才會被set value,因此您不需要再做map.containsKey是否成立或
idMapSalary map利用IntStream進行走訪來put value,若是使用一般的put method,id 1, 2的
value將會被覆蓋掉,而利用putIfAbsent,第一個參數為key, 第二個參數為value,這個value
值可自行put至key id 3,4裡面
DEMO 如下
1
No.1 hour sallary=140
2
No.2 hour sallary=150
3
No.3 hour sallary=140
4
No.4 hour sallary=130
從執行結果可以得知,所有的key皆會被走訪,但是已存在有效value的key,其值並不會有
所變動! 而請注意! putIfAbsent的回傳值可能為value or null,null的例子為id 3,4在第一
次put後! 之後皆會像id 1, 2一樣回傳其value值!
#computeIfAbsent- 初始化map時可使用,value → null的key被走訪
類似於putIfAbsent的功用,只不過在參數2會建立lambda運算式,此時滿足的key其
value → null才成立,帶入這個key之後您可以進行相關的運算,如可能帶入這個key從別的
map取得對應的newValue等等!
官方解說如下:
如上所述,假設求得的newValue本身若是為null,那也沒有必要再做put的動作了
範例程式碼如下:
與computeIfPresent帶入的參數形式是一樣的!
DEMO如下
1
No.1 hour sallary=160
2
No.2 hour sallary=150
3
No.3 hour sallary=160
4
No.4 hour sallary=130
5
No.5 hour sallary=160
6
No.6 hour sallary=130
7
No.7 hour sallary=null
8
No.8 hour sallary=null
從執行結果可以得知,所有的id皆會進行走訪,由於method addHourSalaryForOddId無法針
對oldValue → null的值進行處理,因此使得id 7,8的newValue還是null
#merge - 初始化map時可使用,所有key皆會被走訪
這個method比較特別的地方是確保key → value = null也可以帶入預設值,但是只有針對
key → value != null的value會進入lambda expression的走訪!
官方解說如下:
範例程式碼如下:
merge method的參數新增為三個,帶入了key, value, lambda expression
特別的是這個value的作用因為兩種情況而有不一樣的走向
1. map.get的值(oldValue)為null時,直接map.put(key, value)
2. map.get的值(oldValue)不等於null時,就會進入lambda expression的運算
DEMO如下
No.1 hour sallary=130
No.2 hour sallary=130
No.3 hour sallary=130
No.4 hour sallary=140
No.5 hour sallary=130
No.6 hour sallary=140
No.7 hour sallary=130
No.8 hour sallary=130
從執行結果可以得知,id 7,8只會帶入預設值130
總結
Map提供的新方法雖然可以讓您少了很多邏輯判斷上對於map的處理,不過請注意Map內
對應的value若是Integer的型態時,有可能會是null的情況,連帶的在lambda expression呼叫
的method參數可能需要宣告為Integer而並非是int型態!
以compute來看,因為key → value = null也會進入lambda expression
此時將帶入的value = null,若呼叫前沒先過濾掉value == null不處理,帶入後value又進行
運算會有NullPointerException問題發生!
method及Lambda語法可以使冗長的判斷程式碼縮短至一行就可以了!
在此將提到的是
這些方法所對應到的行為,裡面的實作已包含我們平常會用到的判斷式!
而官方的API說明還特別列出相關的pseudo code來解說這些method
若您需要使用到的話可以先從這裡來了解!
PS. 在帶入相關的參數中,還可能會利用到Lambda語法! 請先了解一下這個部分囉!
這裡會從一個範例承上啟下的逐步說明下去,講解到這些method被使用到的話,會間接造
成什麼樣的結果,以此就可以判斷哪些method該用到實際應用的什麼地方上!
#putIfAbsent - 初始化map時可使用,所有key皆會被走訪
若key → value == null 才會被set value,因此您不需要再做map.containsKey是否成立或
map.get(...)是否等於null的判斷,這些判斷本身是避免造成已有value的key其值被覆寫調!
官方解說如下:
V v = map.get(key);
if (v == null)
v = map.put(key, value);
return v;
範例程式碼如下:
static Map<String, Integer> idMapSalary;
public static void main(String[] args) {
int basic_salary = 130;
idMapSalary = new HashMap<String, Integer>();
idMapSalary.put("1", 140);
idMapSalary.put("2", 150);
IntStream.range(1, 5)
.mapToObj(i -> String.valueOf(i))
.forEach(i -> {
idMapSalary.putIfAbsent(i, addHourSalaryForOddId(i, basic_salary));
printResult(i, idMapSalary.get(i));
});
}
public static void printResult(String id, Integer value){
System.out.println("No."+id+" hour sallary="+value);
}
public static Integer addHourSalaryForOddId(String id, Integer salary){
System.out.println(id);
if(salary != null)
return (Integer.parseInt(id) % 2 == 1) ? salary + 10 : salary;
return salary;
}
idMapSalary map利用IntStream進行走訪來put value,若是使用一般的put method,id 1, 2的
value將會被覆蓋掉,而利用putIfAbsent,第一個參數為key, 第二個參數為value,這個value
值可自行put至key id 3,4裡面
DEMO 如下
1
No.1 hour sallary=140
2
No.2 hour sallary=150
3
No.3 hour sallary=140
4
No.4 hour sallary=130
從執行結果可以得知,所有的key皆會被走訪,但是已存在有效value的key,其值並不會有
所變動! 而請注意! putIfAbsent的回傳值可能為value or null,null的例子為id 3,4在第一
次put後! 之後皆會像id 1, 2一樣回傳其value值!
#computeIfAbsent- 初始化map時可使用,value → null的key被走訪
類似於putIfAbsent的功用,只不過在參數2會建立lambda運算式,此時滿足的key其
value → null才成立,帶入這個key之後您可以進行相關的運算,如可能帶入這個key從別的
map取得對應的newValue等等!
官方解說如下:
if (map.get(key) == null) {
V newValue = mappingFunction.apply(key);
if (newValue != null)
map.put(key, newValue);
}
如上所述,假設求得的newValue本身若是為null,那也沒有必要再做put的動作了
範例程式碼如下:
IntStream.range(1, 7)
.mapToObj(i -> String.valueOf(i))
.forEach(i -> {
printResult(i, idMapSalary.computeIfAbsent(i, key ->
addHourSalaryForOddId(key, basic_salary)));
});
同樣利用IntStream來進行走訪,此時再增加兩個id 5,6做初始化給值動作
DEMO如下
No.1 hour sallary=140
No.2 hour sallary=150
No.3 hour sallary=140
No.4 hour sallary=130
5
No.5 hour sallary=140
6
No.6 hour sallary=130
從執行結果可以得知,key → value != null的id皆不會進入computeIfAbsent的第二個參數內
,因此執行addHourSalaryForOddId method的key只有5, 6。
請注意! computeIfAbsent的回傳值,不像putIfAbsent,id 5, 6在初始化其值之後,回傳的值
也就是這個newValue,而不是null
#computeIfPresent - 針對map value != null的key進行走訪
相對於computeIfAbsent,這個method所執行的是value != null的key來進行走訪,相對地value
→ null的key則不會有任何動作! 但是若經過走訪後的key得到的value = null的話,則這個key
將會被remove掉!(很合理!)
官方解說如下:
如上所述,這個method需注意的是第二個參數的lambda expression,將會帶入
DEMO如下
No.1 hour sallary=140
No.2 hour sallary=150
No.3 hour sallary=140
No.4 hour sallary=130
5
No.5 hour sallary=140
6
No.6 hour sallary=130
從執行結果可以得知,key → value != null的id皆不會進入computeIfAbsent的第二個參數內
,因此執行addHourSalaryForOddId method的key只有5, 6。
請注意! computeIfAbsent的回傳值,不像putIfAbsent,id 5, 6在初始化其值之後,回傳的值
也就是這個newValue,而不是null
#computeIfPresent - 針對map value != null的key進行走訪
相對於computeIfAbsent,這個method所執行的是value != null的key來進行走訪,相對地value
→ null的key則不會有任何動作! 但是若經過走訪後的key得到的value = null的話,則這個key
將會被remove掉!(很合理!)
官方解說如下:
if (map.get(key) != null) {
V oldValue = map.get(key);
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null)
map.put(key, newValue);
else
map.remove(key);
}
如上所述,這個method需注意的是第二個參數的lambda expression,將會帶入
key and value(OldValue),由此看來這個method比較像是在執行map的運算!
範例程式碼如下:
IntStream.range(1, 9)
.mapToObj(i -> String.valueOf(i))
.forEach(i -> {
printResult(i, idMapSalary.computeIfPresent(i, (key, val) ->
addHourSalaryForOddId(key, val)));
});
同樣利用IntStream來進行走訪,此時再增加兩個id 7,8,只不過這兩個id將無法進行初始化!
DEMO如下
1
No.1 hour sallary=150
2
No.2 hour sallary=150
3
No.3 hour sallary=150
4
No.4 hour sallary=130
5
No.5 hour sallary=150
6
No.6 hour sallary=130
No.7 hour sallary=null
No.8 hour sallary=null
從執行結果可以得知,id 1 ~ 6將進行computeIfPresent內第二個參數lambda expression的運算!
#compute - 所有的key皆會進行走訪
不管您的map key → value是否為null,皆進行lambda expression處理,取得的newValue
只有是null時才不進行put動作,但key是存在的將會remove掉(很合理)
官方解說如下:
看起來蠻複雜的,不過只要了解computeIfAbsent and computeIfPresent怎麼使用後,compute
DEMO如下
1
No.1 hour sallary=150
2
No.2 hour sallary=150
3
No.3 hour sallary=150
4
No.4 hour sallary=130
5
No.5 hour sallary=150
6
No.6 hour sallary=130
No.7 hour sallary=null
No.8 hour sallary=null
從執行結果可以得知,id 1 ~ 6將進行computeIfPresent內第二個參數lambda expression的運算!
#compute - 所有的key皆會進行走訪
不管您的map key → value是否為null,皆進行lambda expression處理,取得的newValue
只有是null時才不進行put動作,但key是存在的將會remove掉(很合理)
官方解說如下:
V oldValue = map.get(key);
V newValue = remappingFunction.apply(key, oldValue);
if (oldValue != null ) {
if (newValue != null)
map.put(key, newValue);
else
map.remove(key);
} else {
if (newValue != null)
map.put(key, newValue);
else
return null;
}
就蠻好理解的!
範例程式碼如下:
IntStream.range(1, 9)
.mapToObj(i -> String.valueOf(i))
.forEach(i -> {
printResult(i, idMapSalary.compute(i, (key, val) ->
addHourSalaryForOddId(key, val)));
});
與computeIfPresent帶入的參數形式是一樣的!
DEMO如下
1
No.1 hour sallary=160
2
No.2 hour sallary=150
3
No.3 hour sallary=160
4
No.4 hour sallary=130
5
No.5 hour sallary=160
6
No.6 hour sallary=130
7
No.7 hour sallary=null
8
No.8 hour sallary=null
從執行結果可以得知,所有的id皆會進行走訪,由於method addHourSalaryForOddId無法針
對oldValue → null的值進行處理,因此使得id 7,8的newValue還是null
#merge - 初始化map時可使用,所有key皆會被走訪
這個method比較特別的地方是確保key → value = null也可以帶入預設值,但是只有針對
key → value != null的value會進入lambda expression的走訪!
官方解說如下:
V oldValue = map.get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if (newValue == null)
map.remove(key);
else
map.put(key, newValue);
範例程式碼如下:
IntStream.range(1, 9)
.mapToObj(i -> String.valueOf(i))
.forEach(i -> {
printResult(i, idMapSalary.merge(i, basic_salary, (oldValue, Value) ->
(oldValue <= Value) ? oldValue + 10 : Value));
});
merge method的參數新增為三個,帶入了key, value, lambda expression
特別的是這個value的作用因為兩種情況而有不一樣的走向
1. map.get的值(oldValue)為null時,直接map.put(key, value)
2. map.get的值(oldValue)不等於null時,就會進入lambda expression的運算
DEMO如下
No.1 hour sallary=130
No.2 hour sallary=130
No.3 hour sallary=130
No.4 hour sallary=140
No.5 hour sallary=130
No.6 hour sallary=140
No.7 hour sallary=130
No.8 hour sallary=130
從執行結果可以得知,id 7,8只會帶入預設值130
總結
Map提供的新方法雖然可以讓您少了很多邏輯判斷上對於map的處理,不過請注意Map內
對應的value若是Integer的型態時,有可能會是null的情況,連帶的在lambda expression呼叫
的method參數可能需要宣告為Integer而並非是int型態!
以compute來看,因為key → value = null也會進入lambda expression
此時將帶入的value = null,若呼叫前沒先過濾掉value == null不處理,帶入後value又進行
運算會有NullPointerException問題發生!
留言
張貼留言