map中value統一自增或自減的優雅寫法

weixin_33797791發表於2018-11-20

2019-01-06 一種更優雅的方式 replaceAll()

需求: 對map中的所有值統一增減

基礎版本

下面這個方式是可行的,但是看著不太優雅

    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap<>();
        map.forEach((key, value)->map.put(key,map.get(key)-1));
    }
複製程式碼

誤用版本--merge 有副作用

經過一番研究之後發現了一種簡單的方式,但是有個限制 merge之後不能發生結構性修改(也就是map中元素數量不能發生變化),在當前場景下只要保證merge後不為空值即可

public class MapIncr {
    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap<>();
        map.forEach((key, value) -> map.merge(key, -1, Integer::sum));
    }
}
複製程式碼

關鍵就是map.merge(),原始碼如下

    default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        V oldValue = get(key);
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        if(newValue == null) {
            remove(key);
        } else {
            put(key, newValue);
        }
        return newValue;
    }
複製程式碼

可以看到如果新值為空就會被移除掉

最佳版本--replaceAll

replaceAll會對map中的所有元素使用傳遞進來的BiFunction進行更新.

public class MapIncr {
    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap<>();
        map.replaceAll((k,v)->v+1);
    }
}
複製程式碼

總結

  • 基礎版本的偏向於指令式程式設計,遍歷map,對map中的每個元素進行處理,處理規則是,這需要使用者說明並編寫整個處理流程.
  • 最佳版本則更符合函數語言程式設計,我想替換map中的所有值,替換規則是xxx,隱藏了遍歷邏輯.很明顯,最佳版本的更加清楚明瞭.
  • 至於誤用版本,就是對api的錯誤使用了,之所以保留它,只是想說明: keep digging,there is always a better way,

相關文章