Collectors.toMap異常
在使用Collectors.toMap方法時,會有兩個常見的問題:1. 鍵衝突,導致拋出異常 2. 值爲NULL,導致拋出空指針異常
下面給出上面兩種問題的解決方案。
鍵衝突 ?
有三種策略,分別如下:
-
用後面的value覆蓋前面的value
Map<String, String> map = list.stream.collect(Collectors.toMap(Student::getName, Student::getAge, (key1, key2)->key2));
同理,如果
(key1, key2)->key1
則表示用前面的value覆蓋後面的value,即保持不變。 -
將重複key的value進行拼接
Map<String,String> map = list.stream.collect(Collectors.toMap(Student::getName, Student::getAge, (key1, key2)->key1 + "," + key2))
-
將重複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);
常見的解決方法如下:
-
Map<Long, String> memberMap = list.stream().collect(HashMap::new, (m, v) -> m.put(v.getId(), v.getName()), HashMap::putAll);
-
自定義map集合,對list進行foreach遍歷,依次取出其對應的屬性存放爲map的key和value。
-
繼承Collector,手動實現toMap方法,然後調用我們自己封裝的toMap方法就可以了。
有關實現Collector,參考鏈接
(另,對於key衝突拋出異常,已經在jdk9中得到解決,參考鏈接)