Collectors方法常见的异常
2024-01-02 13:30:39
1. Collectors.toMap常见的异常
1.1 Collectors.toMap 报错 NullPointerException
最近线上偶尔会报一个 NPE,是 Collectors.toMap 导致的,这里小记一下,防止再次踩坑。
场景:批量查询用户信息,查询结果为 List<User>
,然后将其转换成 Map<Integer, String>
,以供其他地方使用,但在 Collectors.toMap 时抛出了异常 NullPointerException
。
1.1.1复现问题
public class ToMapTest {
public static void main(String[] args) {
List<User> users = query();
Map<Integer, String> userMap = users.stream()
.collect(Collectors.toMap(User::getId, User::getGirlfriend));
}
public static List<User> query() {
List<User> list = new ArrayList<>();
// girlfriend 为 null
list.add(new User(1, null));
return list;
}
}
@Data
class User {
private final Integer id;
private final String girlfriend;
}
当 User 的 girlfriend 为 null 时,会抛出 NPE(单身狗落泪!!!)
Exception in thread "main" java.lang.NullPointerException
at java.util.HashMap.merge(HashMap.java:1225)
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:499)
at com.example.collectors.ToMapTest.main(ToMapTest.java:19)
原因
在第 16 行,会调用 map.merge,且两个参数的 toMap 方法默认是创建 HashMap(第 5 行)。
// Collectors.toMap
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);
}
// 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.merge 方法
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
原因很简单,第 4 行判断了 value == null,所以抛出了 NullPointerException。
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (value == null)
throw new NullPointerException();
if (remappingFunction == null)
throw new NullPointerException();
......
}
1.1.2 解决办法
以下两种方法与 Collectors.toMap 方法的区别是:当出现重复的 key 时, Collectors.toMap 默认会抛异常,而以下两种方式会用新值覆盖旧值。
// Collectors.toMap 默认抛异常
private static <T> BinaryOperator<T> throwingMerger() {
return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}
Stream.collect 方法
Stream 的 collect 可以实现简易的 Collector 功能:
// Stream.collect()
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
public static void main(String[] args) {
List<User> users = query();
Map<Integer, String> userMap2 = users.stream()
.collect(HashMap::new, (map, user)->
map.put(user.getId(), user.getGirlfriend()), HashMap::putAll);
System.out.println(userMap2);
}
// 输出
// {1=null}
直接使用 Collector
与使用 Stream.collect 方法相比,Collector多了一个 Characteristics 参数,这里用不到所以给了空数组:
public static void main(String[] args) {
List<User> users = query();
Collector<User, Map<Integer, String>, Map<Integer, String>> collector = Collector.of(
HashMap::new,
(map, user)-> map.put(user.getId(), user.getGirlfriend()),
(map1, map2) -> {
map1.putAll(map2);
return map1;
},
new Collector.Characteristics[]{}
);
Map<Integer, String> userMap2 = users.stream()
.collect(collector);
System.out.println(userMap2);
}
// 输出
// {1=null}
鸣谢:https://blog.csdn.net/qq_20919883/article/details/119654002
文章来源:https://blog.csdn.net/CNCDXX_88/article/details/135332871
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!