別再這麼寫程式碼了,這幾個方法不香嗎?
JDK8 應該是 Java 中最堅挺一個版本,這個版本新增很多特性,讓我們開發起來多了很多便利。
不過最近 Review 專案程式碼的時候發現,雖然很多專案工程已經使用了 JDK8,但是工程程式碼卻很少使用到 JDK8 新特性、新方法。
如果單從程式碼正確性上來說,老方式寫法寫當然沒有什麼問題,那唯一的缺點其實就是程式碼行數比較多,比較繁瑣。
那同樣的需求,使用 JDK8 新方法,其實幾行程式碼就可以搞定,這樣程式碼就會變得非常簡潔。
今天就以三個比較常見的場景為例,教你幾招,使用 JDK8 Map
新增的方法簡化程式碼開發。
下面就來看看這次即將用到 Map
幾個新方法:
> 歡迎關注我的公眾號:小黑十一點半,獲得日常乾貨推送。
預防空指標問題
日常開發中我們通常會從 Map
獲取元素,然後進行相關的業務處理,示例程式碼如下:
Map map = new HashMap();
map.put("公號", "小黑十一點半");
map.put("主理人", "樓下小黑哥");
// 可能存在 NPE 問題
System.out.println(map.get("支付").toUpperCase());
如果就像示例程式碼直接處理,一旦 Map
中相應元素不存在,那麼我們就會碰到空指標問題。
為了解決這個問題,通常我們可以先判斷一下元素是否為 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(),"支付", "");
巧用 computeIfAbsent
日常開發中,我們會碰到這類場景,需要一個鍵需要對映到多個值,這個時候我們可以使用 Map>
這個結構。
此時新增元素的時候,我們需要做一些判斷,當內部元素不存在時候主動建立一個集合物件,示例程式碼如下:
Map> map = new HashMap();
List 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 multiset= ArrayListMultimap.create();
multiset.put("java框架","Spring");
multiset.put("java框架","Mybatis");
// java框架--->Spring,Mybatis
單詞統計
假設有如下需求,我們需要統計一段文字中相關單詞出現的次數。那實現方式其實很簡單,使用 Map
儲存相關單詞的次數即可,示例程式碼如下:
Map 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() {
@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
函式,不熟悉的話,其實比較難以理解程式碼。
不過也還好,我們只要在日常編碼過程中,刻意去練習使用,很快就能上手。
最後,JDK8 還有許多好用方法,刻意簡化程式碼開發,你可以在留言區推薦幾個嗎?
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1834/viewspace-2827013/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 這些手寫程式碼會了嗎?少年
- 別瞎寫工具類了,Spring自帶的不香嗎?Spring
- Android:寫了這麼多程式碼,你真的理解泛型嗎Android泛型
- 對不起,我錯了,這程式碼不好寫
- 救救自己,別再這樣寫簡歷了
- 別再眼高手低了! 這些Linq方法都清楚地掌握了嗎?
- 一個新手怎麼做自媒體?這幾個要素你掌握了嗎?
- 別再問我 WiFi 密碼了:這兩個 GitHub 幫你解決WiFi密碼Github
- 騰訊獨代不香了嗎?
- 寫程式碼做副業月入10K+的方法都藏在這幾個公眾號
- Python 程式碼寫得醜怎麼辦,試試這幾款神器Python
- 別問了,我真的不喜歡這個註解!
- 低程式碼這麼火,它的人才認證你考了嗎?
- 誰說這程式碼爛啊,這程式碼太棒了!
- 這個框架停止維護了嗎?框架
- Redis系列總結--這幾點你會了嗎?Redis
- 因為這幾個TypeScript程式碼的壞習慣,同事被罰了500塊TypeScript
- 別再翻了,面試二叉樹看這 11 個就夠了~面試二叉樹
- 要炸了!剛寫完這段程式碼,就被開除了
- 評審程式碼時,這樣寫就不會被懟了
- 收藏好這篇,別再只說“資料劫持”了
- 懶得寫文件,swagger文件匯出來不香嗎Swagger
- 做了這麼多年前端,為什麼你還是不會寫業務程式碼?前端
- 答應我,用了這個jupyter外掛,別再重複造輪子了
- Java老碼農心得:捲了這麼多年,您真的卷會了嗎?Java
- 這幾種Java異常處理方法,你會嗎?Java
- 人工智慧如此高薪,這10個AI開源專案它不香嗎?人工智慧高薪AI
- 4大密碼管理器再曝漏洞,你用的是這個嗎?密碼
- 寫了 50 萬行 Go 程式碼後,我明白這些道理Go
- Linux程式間通訊有幾種方式?這8個你都知道嗎?Linux
- 寫1行程式碼影響1000000000人,這是個什麼專案?行程
- Spring 快取註解這樣用,太香了!Spring快取
- 想幫助改善 GNOME 嗎?這個新工具給了你這個機會!
- 這個太簡單了,我也不會
- 二次封裝這幾個 element-ui 元件後,讓程式碼更加優雅了封裝UI元件
- 寫了這麼多年 JavaScript ,竟然還不知道這些技巧?JavaScript
- 有了Git這個操作,我再也不怕程式碼混亂了!Git
- 這幾個換臉 GitHub 專案太牛了!Github