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); }總之,函式式方法使用的函式應該足夠簡單,便于理解,
如果使用默認方法可以簡化了理解,代碼更簡潔,而且沒有副作用,確保代碼兼容性,可以使用默認方法,其他情況下還是老老實實用命令式編程吧,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/457588.html
標籤:Java
