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

firefule發表於2021-09-09

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有一個好處,針對傳入 Mapnull 的情況,可以設定預設值。

假設我們是從 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) {

如果 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 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。

那如果 javacountMap 中存在,則會呼叫第三個引數 remappingFunction 函式方法進行計算。

remappingFunction 函式中,oldValue代表原先 countMapjava 的值,newValue代表我們設定第二個引數 1,這裡我們將兩者相加,剛好完成累加的需求。

最後

這次主要從個人日常碰到三個場景出發,給大家對比了一下使用 JDK8 Map 新增方法只會,兩者程式碼區別。

從上面可以很明顯看出,使用新增方法之後,我們可以用很少的程式碼可以完成,整體看起來變得非常簡潔。

不過 JDK8 之後很多方法都會用到 lambda 函式,不熟悉的話,其實比較難以理解程式碼。

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

最後,JDK8 還有許多好用方法,刻意簡化程式碼開發,你可以在留言區推薦幾個嗎?

圖片描述

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1834/viewspace-2827013/,如需轉載,請註明出處,否則將追究法律責任。

相關文章