Java Lambda Map篇

目的

主要介紹Map中的新方法,包含如下

  • forEach()
  • getOrDefault()
  • putIfAbsent()
  • remove()
  • replace()
  • replaceAll()
  • merge()

有些是Lambda有些則是我覺得比以前使用Map更方便而介紹


forEach

Map的forEach方法與List不大依樣,因為Map主要的迭代方法是以Entry為主,所以需要Key-Value Pair去迭代

原始碼解說

可以看到forEach的傳入參數BiConsumer介面,必須傳入Key與Val,裡面的實作就如同我們使用Java8版本以前的寫法,需要使用for迴圈去迭代抓出每個Value

原始碼

default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k;
        V v;
        try {
            k = entry.getKey();
            v = entry.getValue();
        } catch(IllegalStateException ise) {
            // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }
        action.accept(k, v);
    }
}

範例

    private void forEachExample() {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "test1");
        map.put(2, "test2");
        map.forEach((k,v) -> {
            System.out.println("Key : " + k + "- Value : " + v);
        });
    }

getOrDefault

getOrDefault其實和Lambda沒有太多的關聯,不過!這個方法實在是很好用,我們不須再去判斷Map裡面的Value值是不是存在了,可以直接透過此方法回傳我們想預設的值

範例

    private void getOrDefaultExample() {
        Map<Integer, String> map = new HashMap<>();
        System.out.println(map.getOrDefault(1, "NO_VALUE"));
    }

putIfAbsent

如同getOrDefault,都是功能性的方法,當Key對應的值不存在的話,才放入傳入的值

範例

    private void putIfAbsentExample() {
        Map<Integer, String> map = new HashMap<>();
        map.putIfAbsent(1, "original");
        map.putIfAbsent(1, "new");
        System.out.println(map.getOrDefault(1, "NO_VALUE"));
    }

上面的範例,如果實際跑的話可以看到我們拿出來的值是original

remove

其實map本身就有remove參數了,但是他多了一個新的方法,原始碼如下

原始碼解析

可以看到此方法,會將第二個value參數帶入判斷,如果相同才會刪除

原始碼

    default boolean remove(Object key, Object value) {
        Object curValue = get(key);
        if (!Objects.equals(curValue, value) ||
            (curValue == null && !containsKey(key))) {
            return false;
        }
        remove(key);
        return true;
    }

範例

    private void removeExample() {
        Map<Integer, String> map = new HashMap<>();
        map.putIfAbsent(1, "original");
        map.putIfAbsent(2, "new");
        map.remove(1, "error_value");
        map.remove(2);
        System.out.println(map.getOrDefault(2, "NO_VALUE"));
        System.out.println(map.getOrDefault(1, "NO_VALUE"));
    }

replace

replace方法與put方法相似,但重點就如同方法的名稱一樣"替換",當今天此key對應的value存在時才會進行替換,而此方法也提供了三個參數的功能,如果原本存在的Value是這個的話才會進行替換

範例

    private void replaceExample() {
        Map<Integer, String> map = new HashMap<>();
        map.putIfAbsent(1, "original");
        map.putIfAbsent(2, "original2");
        map.replace(1, "new");
        map.replace(2, "original", "new");
        map.forEach((k,v)->{
            System.out.println(v);
        });
    }

可以看到上面的範例,original2並不會被new值替換,因為不符合輸入的條件(original)

replaceAll

言簡意賅,直接對Map中的Value值做Side effect處理

範例

    private void replaceAll() {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "original");
        map.put(2, "original2");
        map.replaceAll((k, v) -> v.toUpperCase());
        map.forEach((k, v) -> {
            System.out.println(v);
        });
    }

merge

merge與replace方法相似,主要差別在於如果原本有值的話則對舊值與新值作傳入的方法處理

範例

    private void mergeExample() {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "test");
        map.merge(1, "new_test", (v1, v2) -> v1 + "-" + v2);
        map.forEach((k, v) -> {
            System.out.println(v);
        });
    }

結論

文章介紹了七個Map方法,如果可以實踐的話相信在處理Map結構上,程式碼一定可以更簡潔

留言

這個網誌中的熱門文章

(InterviewBit) System Design - Design Cache System

設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)