Spring 簡介 spring,英文單詞為春天,表示為軟體行業帶來了春天。 2002年,首次推出了Spring框架的雛形:interface21框架。官網為:www.interface21.io但是現在進去時間略長。 Spring框架是以上面這個框架為基礎重新設計,並不斷對其進行改進豐富其內涵,在 ...
Map介面總結(如何使用預設方法)
-
基本操作
get
put(區別:Collection介面中添加為set)
putAll
remove
containsKey
containsValue
size
clear
-
遍歷操作
keySet()
values()
entrySet()
-
實現規約
以下兩個方法提示實現類需要重寫用來比較相等的方法。
equals
hashcode
以下兩個方法是標準庫的約定,但是Java中介面不支持定義構造器約束,只能保證標準庫中都實現了這兩個方法。
構造器(空參數)
構造器(Map other)
-
default方法
排序在前的方法較為常用。
預設方法是為了在標準庫中添加預設支持函數式方法,同時也不必修改現有的類,這樣做雖然有一定的好處,但是實際上在子類中使用default方法還是極有可能出錯的,因為一個default方法無法滿足所有的子類,也不可能滿足。如果隨意使用default方法,可能破壞了原有子類的一致性,產生意想不到的問題。
在標準庫中,除了併發相關類,比如ConcurrentHashMap等,一般沒有問題。
但是在其他類庫的實現類中使用一定要慎之又慎,比如使用一個老版本的Map子類。
引入default方法破壞了前向相容性,容易產生運行時異常。
V getOrDefault(Object key, V defaultValue)
常用,獲取值或者預設值,可類比Optional.orElse。以下是先做判斷,後計算的(if true)
V putIfAbsent(K key, V value)
V replace(K key, V value)
感覺叫putIfPresent更好boolean replace(K key, V oldValue, V newValue)
boolean remove(Object key, Object value)
如果匹配的話,remove以下四個方法為一組,都是對entry(k, v)的更新,只是條件不一樣。
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) // 如果沒有entry則更新 // 返回值為value,可以用於後續操作 // 常用於MultiMap,如下麵一句話表示把用戶添加到用戶組裡 map.computeIfAbsent(userGroup, k -> new HashMap<User>()).add(user);
V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) // 如果有entry則更新
V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) // 不常用,因為如果不包含entry則可能拋出空指針異常 // 可以理解為同時支持上面兩個方法,但是我們一般都需要對是否包含entry進行判斷,所以不常用。 // compute方法也可以實現merge這樣的規約操作,既然如此,在需要規約操作時,我們為什麼不用merge呢。 // v 可能為空指針,程式員極有可能忘記檢查,編譯器也不能幫助檢查。 // 總之,這個compute方法不常用。 // compute進行null判斷 map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg)) // merge中更簡單 map.merge(key, msg, String::concat)
V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) // 沒有則使用預設值,有則進行類似reduce的操作 // 規約結果為null時,則刪除 // 好用 // 常用來計數 map.merge(key, 1, Integer::sum);
void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) // 使用泛型達到了更廣的匹配 // 通配符使用原則,使用的對象 (consumer) 使用 super,生成的對象 (provider) 使用 extends。
forEach(BiConsumer<? super K, ? super V> action)
!!!經常濫用的方法,不建議使用,action只建議使用簡單的邏輯。每回看到別人使用forEach方法都感覺很噁心,這個方法看上去好用,可以傳入(k,v)→ ... lambda表達式,但是函數式方法應該儘量不產生副作用,使用函數式方法的目的應該便於理解。然而在項目中經常看到大段的lambda表達式傳入,在不便於調試的同時,還不能產生副作用。由於副作用的問題,每回想修改forEach的邏輯時,都必須改為for (Map.Entry<K, V> entry : map.entrySet()),然後再修改邏輯。
包括Collections下的List,Set等都有濫用forEach方法。
以下是我在網上找的一個例子,不知道你看到forEach後啥感覺,我反正是要吐了,況且這還是一段邏輯相對簡單的代碼。
public static void main(String[] args) { // create a HashMap and add some values HashMap<Integer, String> map1 = new HashMap<>(); map1.put(1, "Ram"); map1.put(2, "Rohan"); map1.put(3, "Shivam"); HashMap<Integer, String> map2 = new HashMap<>(); map2.put(1, "Tushar"); map2.put(10, "Satya"); map2.put(12, "Sundar"); // print map details System.out.println("HashMap1: " + map1.toString()); System.out.println("HashMap2: " + map2.toString()); // provide value for new key which is absent // using computeIfAbsent method map2.forEach( (key, value) -> map1.merge( key, value, (v1, v2) -> v1.equalsIgnoreCase(v2) ? v1 : v1 + ", " + v2)); // print new mapping System.out.println("New HashMap: " + map1); }
總之,函數式方法使用的函數應該足夠簡單,便於理解。
如果使用預設方法可以簡化了理解,代碼更簡潔,而且沒有副作用,確保代碼相容性,可以使用預設方法,其他情況下還是老老實實用命令式編程吧。