Java 8 流收集器打破了 HashMap 插入语义?



所以我正在尝试使用Java 8流Collectors.toMap将元素添加到新创建的Map中。

要创建的映射可能包含其某些键的空值。这对于 HashMap 来说是完全可以接受的,当我使用 for Each 的流来添加成员时,它按预期工作:

    final Map<String, Method> rMap = new HashMap<> ( );
    msgRouteProps.entrySet ( )
                 .stream ( )
                 .forEach (entry -> rMap.put (entry.getKey ( ),
                                              ReflectionUtil.getNamedMethod (processor, entry.getValue ( ))));

msgRouteProps 是一个映射,其中键和值都是非空的。请注意,ReflectionUtil.getNamedMethod (( 调用可能会返回一个 null,我希望将其放入生成的 Map 中。

所以我想探索如何使用 Collectors.toMap(( 方法做同样的事情,这样流操作就可以返回新创建的映射,而无需我直接创建它。

所以我尝试了以下方法:

Map<String, Method> rMap = 
    msgRouteProps.entrySet ( )
                 .stream ( )
                 .collect (Collectors.toMap (Map.Entry::getKey,
                                             (e) -> ReflectionUtil.getNamedMethod (processor, e.getValue ( ))));

在我看来,这应该以同样的方式工作,但不幸的是,它失败并出现空指针异常。看起来 Collectors.toMap 方法调用了 HashMap 的 merge(( 方法,该方法不允许传递空值。对我来说似乎很奇怪的是,我真的不认为在这种情况下应该调用合并,因为原始映射中的键都是唯一的。鉴于此,我假设可以通过调用地图的 put(( 方法简单地将这些值添加到新地图中,该方法将允许空值。

是我在这里做错了什么,还是有解决方法?或者这只是使用 Collectors.toMap 时的预期行为?

这是一个已知的错误,已经被许多用户报告了

最好的方法是在具有空值时使用 forEach。仍然如果您想使用collect请尝试以下解决方法

Map<String, Method> rMap = 
    msgRouteProps.entrySet()
                 .stream()
                 .collect(HashMap::new, (m,v) -> m.put(v.getKey(), ReflectionUtil.getNamedMethod(processor, v.getValue())), HashMap::putAll);

也看看这个答案

最新更新