首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Collections.unmodifiableMap不检查所传递的映射是否已经是UnmodifiableMap?

为什么Collections.unmodifiableMap不检查所传递的映射是否已经是UnmodifiableMap?
EN

Stack Overflow用户
提问于 2019-12-29 07:47:07
回答 3查看 895关注 0票数 6

查看java.util.Collections.unmodifiableMap实现(OpenJDK 11):

代码语言:javascript
复制
    /**
     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
     * specified map. Query operations on the returned map "read through"
     * to the specified map, and attempts to modify the returned
     * map, whether direct or via its collection views, result in an
     * {@code UnsupportedOperationException}.<p>
     *
     * The returned map will be serializable if the specified map
     * is serializable.
     *
     * @param <K> the class of the map keys
     * @param <V> the class of the map values
     * @param  m the map for which an unmodifiable view is to be returned.
     * @return an unmodifiable view of the specified map.
     */
    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
        return new UnmodifiableMap<>(m);
    }

我的问题是,为什么实现不检查所传递的映射是否已经是UnmodifiableMap,如下所示:

代码语言:javascript
复制
    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
        if(m instanceof UnmodifiableMap){
            return m;
        }
        return new UnmodifiableMap<>(m);
    }

相反,这个问题可以扩展到所有其他不可修改的集合,简单的检查有助于避免unwanted stackoverflow errors和不必要的包装。

我想知道为什么没有这样做?

而且,由于UnmodifiableMap是私有的,用户不可能(不使用反射/Classloader魔术)进行检查。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-03-25 19:00:51

实际上,当您使用Java 9或更高版本执行几乎相同的逻辑操作时,通过以下方法,我总是看到这一点也很奇怪:

代码语言:javascript
复制
    Map<String, Integer> left = Map.of("one", 1);
    Map<String, Integer> right = Map.copyOf(left);
    System.out.println(left == right); // true

您可以看到,该实现进行了检查,以查看已知该Map是否已经不可变:

代码语言:javascript
复制
static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map) {
    if (map instanceof ImmutableCollections.AbstractImmutableMap) {
        return (Map<K,V>)map;
    } else {
        return (Map<K,V>)Map.ofEntries(map.entrySet().toArray(new Entry[0]));
    }
}
票数 3
EN

Stack Overflow用户

发布于 2019-12-29 09:46:38

没有好的理由省略支票。一条评论说

可以存在许多其他不可修改的映射类型。

但这也不是很好的理由。如果有人使用不同的实现,检查将是无效的,但仍然没有问题。

不进行检查的唯一原因是性能。然而,instanceof (或类相等)检查相当便宜,并且消除的间接方向很容易抵消。

当前状态是一个错误;应该进行检查,特别是因为UnmodifiableMapprivate,所以不能用用户代码进行测试。

OTOH --这种情况很少见,而且Java非常保守,所以我不认为它会被修复。您可能需要检查错误数据库,以确定是否报告了此问题。

票数 3
EN

Stack Overflow用户

发布于 2019-12-29 07:55:08

我假设您建议的检查没有执行的原因是,创建UnmodifiableMap实例实际上只是在底层地图实例周围创建一个薄包装器,而不是一个深度副本。要创建一个深度不可修改的副本,您必须执行以下操作:

代码语言:javascript
复制
Map<String, String> unmodMap = Collections.unmodifiableMap(new HashMap<>(yourMap));

如果这是实现,那么检查映射引用是否已经指向UnmodifiableMap可能会避免进行深度复制。

在避免第二次(或第三次)包装现有不可修改的映射时,性能可能不会有很大的提高,因此,为了使实现保持简单,创建者只是选择不去检查。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59517676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档