JDK8-Collectors.toMap異常處理

Collectors.toMap異常

在使用Collectors.toMap方法時,會有兩個常見的問題:1. 鍵衝突,導致拋出異常 2. 值爲NULL,導致拋出空指針異常

下面給出上面兩種問題的解決方案。

鍵衝突 ?

有三種策略,分別如下:

  1. 用後面的value覆蓋前面的value

    Map<String, String> map = list.stream.collect(Collectors.toMap(Student::getName, Student::getAge, (key1, key2)->key2));
    

    同理,如果 (key1, key2)->key1則表示用前面的value覆蓋後面的value,即保持不變。

  2. 將重複key的value進行拼接

    Map<String,String> map = list.stream.collect(Collectors.toMap(Student::getName, Student::getAge, (key1, key2)->key1 + "," + key2))
    
  3. 將重複key的value作爲list存儲

    Map<Long, List<String>> map = list.stream().collect(Collectors.toMap(Person::getId,
            person -> {
                List<String> list1 = new ArrayList<>();
                list1.add(person.getName());
                return list1;
            },
            (List<String> value1, List<String> value2) -> {
                value1.addAll(value2);
                return value1;
            }));
    

空指針異常 ?

對於HashMap來說,value是允許爲null的,但是當用java8的stream將list轉換爲map時,默認是不允許值爲null的,通過Collectors.toMap源碼可知,

public static <T, K, U, M extends Map<K, U>>
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方法進行處理,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;
}

可以看到源碼中對value值進行了限定不能爲null,否則拋出空指針異常,Objects.requireNonNull(value),merge方法的作用可以用javadoc註釋進行解釋:

map.merge(key, msg, String::concat);
V oldValue = map.get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if (newValue == null)
     map.remove(key);
 else
     map.put(key, newValue);

常見的解決方法如下:

  1. Map<Long, String> memberMap = list.stream().collect(HashMap::new, (m, v) ->
            m.put(v.getId(), v.getName()), HashMap::putAll);
    
  2. 自定義map集合,對list進行foreach遍歷,依次取出其對應的屬性存放爲map的key和value。

  3. 繼承Collector,手動實現toMap方法,然後調用我們自己封裝的toMap方法就可以了。

    有關實現Collector,參考鏈接

(另,對於key衝突拋出異常,已經在jdk9中得到解決,參考鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章