【问题标题】:Java map.copyOf not using source map comparatorJava map.copyOf 不使用源映射比较器
【发布时间】:2022-10-13 00:17:42
【问题描述】:

我有无数带有自定义键和比较器的地图。我注意到当我使用类似的代码创建地图时

    var map = TreeMap<>( someCustomComparator );

然后,我使用如下代码创建了一个不可变(且小而快)的副本:

    map = Map.copyOf( map );

然后map.get( similarObject ) 无法检索someObject,即使someObjectsimilarObject 在比较器someCustomComparator 下比较相等(“具有相同的等价类”)。

调试 API 我发现 Map.copyOf 返回一个使用 Object::equals 比较键的映射实现,即它不使用用于构造原始映射的比较器(在我的示例中,这将是 someCustomComparator)。显然,当someObjectsimilarObject 不是同一个对象但在someCustomComparator 下具有相同的等价类但Object::equals 没有被覆盖时,这会产生奇怪的结果:

    map.get( similarObject ) ==> someObject

map = Map.copyOf( map ) 指令之前,以及

    map.get( similarObject ) ==> null 

map = Map.copyOf( map ) 指令之后。这是我必须忍受的预期行为还是应该报告 Java 缺陷?

(注意some/similarObject 的类也实现了comparableMap.copyOf 实现也忽略了这一点。)

(我认为这种行为在所有集合 copyOf 实现中都很常见。)

标签: java api dictionary copy comparator


【解决方案1】:

copyOf 方法的规范说明

返回一个不可修改的 Map包含给定地图的条目.

(强调我的)

这意味着只有条目被复制,没有别的。因此,这是预期的行为,而不是错误。

另一方面,正如in the comments 建议的那样,TreeMap 类的构造函数的文档说

构造一个新的树形图,其中包含与指定的排序图相同的映射并使用相同的顺序。此方法以线性时间运行。

参数:

m - 已排序的映射,其映射将放置在此映射中,并且将使用谁的比较器来对这个地图进行排序

(再次强调我的)

【讨论】:

    【解决方案2】:

    除了 Federico 在他的回答中所说的之外,Map 的 Javadoc 在“不可修改的地图”部分也这么说:

    • 映射的迭代顺序未指定,可能会发生变化。

    如果您需要使用相同顺序的不可修改地图,请使用Collections.unmodifiableMap 包装地图。如果你想要一个副本,只需创建一个新的TreeMap,正如 Federico 所说:

    private static <K, V> SortedMap<K, V> copyOf(SortedMap<K, V> map) {
        return Collections.unmodifiableSortedMap(new TreeMap<>(map));
    }
    

    【讨论】:

      【解决方案3】:

      Map 的 API 规范中,Map.get(Object key) 声明:

      “更正式地说,如果这个映射包含从键 k 到值 v 的映射,使得 Objects.equals(key, k),那么这个方法返回 v;否则它返回 null。(最多可以有一个这样的映射。) "

      SortedMap 的 API 规范指出:

      “插入排序映射的所有键必须实现Comparable接口(或被指定的比较器接受)”

      “请注意,如果排序映射要正确实现Map 接口,则排序映射维护的排序(无论是否提供显式比较器)必须与等于一致。”

      当我发布这个问题时,我忘记了后一段。因此,问题中提到的上述行为是可以预料的,即使它很奇怪。因此,要在MapSortedMap 之间获得一致的行为@ 987654331@ 必须被覆盖以与ComparableComparator 一致,它们曾经被使用过。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-09
        • 2015-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-18
        相关资源
        最近更新 更多