簡體   English   中英

在Java8中,Collectors.toMap中的merge函數什么時候觸發?

[英]In Java8, when will the merge function be triggered in Collectors.toMap?

我想變換Hashmap<String,Long>Treemap ,以排序string.length減其鍵(我不能簡單地用treemap.addAll因為我有可能對其他的邏輯,當插入,我想用java8)

代碼如下。 但是當初始 Hashmap 中存在相同長度的鍵時,它會觸發拋出異常的合並函數(我打算這樣做,因為在我的情況下不會有相同的字符串)。 我想知道為什么會觸發合並函數,因為 toMap() 的 JavaDoc 說“如果映射的鍵包含重復項(根據 Object#equals(Object)),則將值映射函數應用於每個相等的元素,並使用提供的合並功能。” 我認為在我的代碼中,“映射鍵”應該是由Entry::getKey映射的 hashMap 中的條目,而不是 TreeMap 比較器中的string.length() 即“abc”!=“def”。 所以它不應該觸發合並。 但?? 我勒個去?

public class TestToMap {

    public static Map<String, Long> map1 = new HashMap<String, Long>() {
        {
            put("abc", 123L);
            put("def", 456L);
        }
    };

    public static void main(String[] args) {
        Map<String, Long> priceThresholdMap = map1.entrySet().stream()
            .collect(Collectors.toMap(Entry::getKey,
                                      Entry::getValue,
                                      throwingMerger(),
                                      () -> new TreeMap<String, Long>(
                                          (a, b) -> {
                                              return a.length() - b.length();
                                          }))); // this will trigger merge function, why?
        //() -> new TreeMap<String, Long>(Comparator.comparingInt(String::length).thenComparing(String::compareTo))));  // but this won't trigger merge function 

    }

    private static <T> BinaryOperator<T> throwingMerger() {
        return (u, v) -> {
            throw new IllegalStateException(String.format("priceThresholdMap has duplicate v1 %s,v2 %s", u, v));
        };
    }
}

當然,它應該觸發合並。 merge 函數用於合並輸出Map具有相同鍵的值,在您的情況下是TreeMap

TreeMap ,如果Comparatorcompare方法返回0 ,則鍵是相同的,因此具有相同長度的兩個鍵被視為相同,並且應合並它們對應的值。

請注意,您的Comparator導致輸出TreeMap無法正確實現Map接口,因為它定義的順序與equals()不一致:

請注意,樹映射維護的排序,就像任何排序映射一樣,以及是否提供顯式比較器,如果此排序映射要正確實現 Map 接口,則必須與 equals 一致

(來自TreeMap Javadoc)

如果要按長度對String進行排序,您仍然可以使用equals

代替

return a.length() - b.length()

return a.length() == b.length() ? a.compareTo(b) : Integer.compare(a.length(),b.length())

現在,具有相同長度的不相等String將按字典順序排序,而具有不同長度的String將按長度排序。

根據 toMap() 源代碼,它創建了一個累加器,它將源流中的每個元素折疊到映射中。

Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) {
        BiConsumer<M, T> accumulator
                = (map, element) -> map.merge(keyMapper.apply(element),
                                              valueMapper.apply(element), mergeFunction);
        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
    }

而在 Map.merge() 中,當 get("def") 將返回存在的 oldValue=123 時,該鍵是“abc”,因為我給 TreeMap 的比較器“def”等於“abc”。 然后 oldValue!=null 調用合並函數。

 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); // call the merge function
        if(newValue == null) {
            remove(key);
        } else {
            put(key, newValue);
        }
        return newValue;
    }

參考: 收集器 toMap 重復鍵

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM