【问题标题】:Java 8 stream collector breaks HashMap insertion semantics?Java 8 流收集器打破了 HashMap 插入语义?
【发布时间】:2019-08-06 16:20:49
【问题描述】:

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

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

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

msgRouteProps 是一个 Map,其中键和值都是非空的。请注意,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 时的预期行为?

【问题讨论】:

    标签: java-stream


    【解决方案1】:

    这是一个已知的bug已经被很多用户举报了

    如果您有空值,最好的方法是使用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);
    

    也可以看看这个answer

    【讨论】:

    • 感谢您的指点。我想我会坚持使用 forEach 直到修复错误。
    • @Steve 我不会等太久的。没有合并功能的toMap 的最新版本根本不使用Map.merge,但如果值为null,它们仍然会重现抛出异常的行为。在这里使用 forEach 是有道理的,尽管使用 Stream API 污染基于 forEach 的方法没有多大意义。 msgRouteProps.forEach((key,value) -&gt; rMap.put(key, ReflectionUtil.getNamedMethod(processor, value))); 更具可读性。
    • @Holger 是的,我就是这么开始的。我将继续使用它,因为 Collectors.toMap 似乎无法满足我的需求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    • 2016-02-09
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多