別再這麼寫代碼了,這幾個方法不香嗎?

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有一個好處,針對傳入 Mapnull 的狀況,能夠設置默認值。

假設咱們是從 POJO對象獲取 Map 參數,這個時候爲了防止空指針,咱們就須要提早作一個空指針的判斷。

不過若是使用 MapUtils,那咱們就不須要判斷是否爲 null,方法內部已經封裝這個邏輯。

MapUtils.getString(pojo.getMap(),"支付", ""); 複製代碼

巧用 computeIfAbsent

平常開發中,咱們會碰到這類場景,須要一個鍵須要映射到多個值,這個時候咱們可使用 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) { 複製代碼

若是 Mapkey 對應的 value 不存在,則會將 mappingFunction 計算產生的值做爲保存爲該 keyvalue,而且返回該值。不然不做任何計算,將會直接返回 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"); 複製代碼

那其實這是錯誤的,當 Mapkey 對應 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。

那若是 javacountMap 中存在,則會調用第三個參數 remappingFunction 函數方法進行計算。

remappingFunction 函數中,oldValue表明原先 countMapjava 的值,newValue表明咱們設置第二個參數 1,這裏咱們將二者相加,恰好完成累加的需求。

最後

此次主要從我的平常碰到三個場景出發,給你們對比了一下使用 JDK8 Map 新增方法只會,二者代碼區別。

從上面能夠很明顯看出,使用新增方法以後,咱們能夠用不多的代碼能夠完成,總體看起來變得很是簡潔。

不過 JDK8 以後不少方法都會用到 lambda 函數,不熟悉的話,其實比較難以理解代碼。

不過也還好,咱們只要在平常編碼過程當中,刻意去練習使用,很快就能上手。



本文首發於java黑洞網,博客園同步更新

相關文章
相關標籤/搜索