JDK8 應該是 Java 中最堅挺一個版本,這個版本新增不少特性,讓咱們開發起來多了不少便利。java
不過最近 Review 項目代碼的時候發現,雖然不少項目工程已經使用了 JDK8,可是工程代碼卻不多使用到 JDK8 新特性、新方法。app
若是單從代碼正確性上來講,老方式寫法寫固然沒有什麼問題,那惟一的缺點其實就是代碼行數比較多,比較繁瑣。框架
那一樣的需求,使用 JDK8 新方法,其實幾行代碼就能夠搞定,這樣代碼就會變得很是簡潔。ide
今天就以三個比較常見的場景爲例,教你幾招,使用 JDK8 Map
新增的方法簡化代碼開發。函數
下面就來看看此次即將用到 Map
幾個新方法:工具
歡迎關注個人公衆號:小黑十一點半,得到平常乾貨推送。若是您對個人專題內容感興趣,也能夠關注個人博客:studyidea.cn編碼
平常開發中咱們一般會從 Map
獲取元素,而後進行相關的業務處理,示例代碼以下:idea
Map<String, String> map = new HashMap(); map.put("公號", "小黑十一點半"); map.put("主理人", "樓下小黑哥"); // 可能存在 NPE 問題 System.out.println(map.get("支付").toUpperCase()); 複製代碼
若是就像示例代碼直接處理,一旦 Map
中相應元素不存在,那麼咱們就會碰到空指針問題。spa
爲了解決這個問題,一般咱們能夠先判斷一下元素是否爲 null
,若是不爲 null
,再作相應的業務處理。指針
// 第一種 if 判空 String value = map.get("支付"); if (!Objects.isNull(value)) { System.out.println(value.toUpperCase()); } 複製代碼
這種方式惟一劣勢就是代碼處理上比較繁瑣,不是很簡潔。
因此針對這種狀況,其實可使用條件運算符,設置一個默認空值,從而避免後續處理髮生空指針。
// 第一種 if 判空 String value = map.get("支付"); // 第二種 條件運算符 value = Objects.isNull(value) ? "" : value; 複製代碼
這種方式比較簡潔,因此平常開發中我比較喜歡用這種方式。
ps: 這裏的前提,空字符串對於業務沒有特殊意義。若是存在特殊意義,那就不能使用這種方式了。
那若是使用 JDK8 ,其實就很方便了,咱們就可使用 Map#getOrDefault
直接代替條件運算符。
// 等同於條件運算符的效果: Objects.isNull(value) ? "" : value; String value = map.getOrDefault("支付",""); 複製代碼
藉助 Map#getOrDefault
一行代碼直接搞定,就是這麼簡單。
若是你還在使用 JDK8 以前的版本,沒辦法使用這個方法。不要緊,咱們能夠藉助 Apache Common-Lang3 提供的工具類 MapUtils
避免空指針。
// Apache MapUtils String value = MapUtils.getString(map, "支付", ""); 複製代碼
MapUtils
這個工具類相對於Map#getOrDefault
有一個好處,針對傳入 Map
爲 null
的狀況,能夠設置默認值。
假設咱們是從 POJO
對象獲取 Map
參數,這個時候爲了防止空指針,咱們就須要提早作一個空指針的判斷。
不過若是使用 MapUtils
,那咱們就不須要判斷是否爲 null
,方法內部已經封裝這個邏輯。
MapUtils.getString(pojo.getMap(),"支付", ""); 複製代碼
平常開發中,咱們會碰到這類場景,須要一個鍵須要映射到多個值,這個時候咱們可使用 Map<K, List<V>>
這個結構。
此時添加元素的時候,咱們須要作一些判斷,當內部元素不存在時候主動建立一個集合對象,示例代碼以下:
Map<String, List<String>> map = new HashMap(); List<String> classify = map.get("java框架"); if (Objects.isNull(classify)) { classify = new ArrayList<>(); classify.add("Spring"); map.put("java框架", classify); } else { classify.add("Spring"); } 複製代碼
上面的代碼比較繁瑣,到了 JDK8,Map
新增一個 computeIfAbsent
方法:
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { 複製代碼
若是 Map
中 key
對應的 value
不存在,則會將 mappingFunction
計算產生的值做爲保存爲該 key
的 value
,而且返回該值。不然不做任何計算,將會直接返回 key
對應的 value。
利用這個特性,咱們能夠直接使用 Map#computeIfAbsent
一行代碼完成上面的場景,示例代碼以下:
map.computeIfAbsent("java框架", key -> new ArrayList<>()).add("Spring"); 複製代碼
那其實 Map
中還有一個方法 putIfAbsent
,功能跟 computeIfAbsent
比較相似。
那剛開始使用的時候,誤覺得可使用 putIfAbsent
完成上面的需求:
// ERROR:會有 NPE 問題 map.putIfAbsent("java框架", new ArrayList<>()).add("Spring"); 複製代碼
那其實這是錯誤的,當 Map
中 key
對應 value
不存在的時候,putIfAbsent
將會直接返回 null
。
而 computeIfAbsent
將會返回 mappingFunction
計算以後的值,像上面的場景直接返回就是 new ArrayList
。
這一點須要注意一下,切勿用錯方法,致使空指針。
最後針對上面這種一個鍵須要映射到多個值,其實還有一個更優秀的解決辦法,使用 Google Guava 提供的新集合類型 Multiset
,以此快速完成一個鍵須要映射到多個值的場景。
示例代碼以下:
ArrayListMultimap<Object, Object> multiset= ArrayListMultimap.create();
multiset.put("java框架","Spring"); multiset.put("java框架","Mybatis"); // java框架--->Spring,Mybatis 複製代碼
假設有以下需求,咱們須要統計一段文字中相關單詞出現的次數。那實現方式其實很簡單,使用 Map
存儲相關單詞的次數便可,示例代碼以下:
Map<String, Integer> countMap = new HashMap(); Integer count = countMap.get("java"); if (Objects.isNull(count)) { countMap.put("java", 1); } else { countMap.put("java", count++); } 複製代碼
這類代碼是否是很熟悉?一樣比較繁瑣。
接下來咱們可使用 JDK8 Map
新增方法進行改造,此次使用上面用過的 getOrDefault
再加 put
方法快速解決,示例代碼以下:
// getOrDefault Integer count = countMap.getOrDefault("java",0); countMap.put("java", count + 1); 複製代碼
那其實咱們還有一種辦法,此次咱們使用 Map#merge
這個新方法,一句代碼完成上述需求,示例代碼以下:
countMap.merge("java", 1, Integer::sum); 複製代碼
說真的,剛看到 merge
這個方法的時候仍是有點懵,尤爲後面直接使用 lambda
函數,讓人不是很好理解。
這裏先將lambda
函數還原成正常類,給你們着重解釋一下這個方法:
countMap.merge("java", 1, new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer oldValue, Integer newValue) { return Integer.sum(oldValue,newValue); } }); 複製代碼
用上面代碼說明一下merge
方法,若是 java
這個值在 countMap
中不存在,那麼將會其對應的 value
設置爲 1。
那若是 java
在 countMap
中存在,則會調用第三個參數 remappingFunction
函數方法進行計算。
remappingFunction
函數中,oldValue
表明原先 countMap
中 java
的值,newValue
表明咱們設置第二個參數 1,這裏咱們將二者相加,恰好完成累加的需求。
此次主要從我的平常碰到三個場景出發,給你們對比了一下使用 JDK8 Map
新增方法只會,二者代碼區別。
從上面能夠很明顯看出,使用新增方法以後,咱們能夠用不多的代碼能夠完成,總體看起來變得很是簡潔。
不過 JDK8 以後不少方法都會用到 lambda
函數,不熟悉的話,其實比較難以理解代碼。
不過也還好,咱們只要在平常編碼過程當中,刻意去練習使用,很快就能上手。