问题
Stream Collectors.toMap 当value为null时报空指针,如下图所示:
public class Demo {
public static void main(String[] args) {
List<Test> list = new ArrayList<>();
list.add(new Test("code1", "name1"));
list.add(new Test("code2", null));
Map<String, String> map = list.stream().collect(Collectors.toMap(Test::getCode, Test::getName));
System.out.println(map);
}
}
@Data
@AllArgsConstructor
class Test {
private String code;
private String name;
}
执行结果:
Exception in thread "main" java.lang.NullPointerException
at java.util.HashMap.merge(HashMap.java:1226)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
at com.scj.test.Demo.main(Demo.java:15)
底层源码:
public final class Collectors {
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
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);
}
}
Collectors.toMap 最终会调用 Map 的 merge 方法,这里会对value进行判空,如果为空,则抛出空指针异常。
public interface Map<K,V> {
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value); // 这里会对value判空,如果为空,则抛出NPE
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if(newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
}
解决
- 方案一:采用下面这种写法
Map<String, String> collect = list.stream().collect(
HashMap::new,
(m, v) -> m.put(v.getCode(), v.getName()),
HashMap::putAll
);
- 方案二:对value进行判空,并给一个默认值
Map<String, String> map = list.stream().collect(Collectors.toMap(
Test::getCode,
e -> Optional.ofNullable(e.getName()).orElse("")
));