【问题标题】:UnsupportedOperationException when adding to a map in kotlin在 kotlin 中添加到地图时出现 UnsupportedOperationException
【发布时间】:2021-11-05 09:00:17
【问题描述】:

当我尝试将项目添加到地图时,由于出现 UnsupportedOperationException,我的应用程序中只发生了一次崩溃。对于堆栈跟踪,似乎实例化的是 AbstractMap 而不是 MutableMap。代码在kotlin中:

val productMap: MutableMap<ProductModel, Int> =
            binding.myView.getProductMap() as? MutableMap<ProductModel, Int>
                ?: mutableMapOf()

            presenter.getProduct()?.let {
                productMap.put(it, 0)
            }

难道是 kotlin/java 在幕后做了一些奇怪的事情,还是我遗漏了什么?

堆栈跟踪:

Fatal Exception: java.lang.UnsupportedOperationException
       at java.util.AbstractMap.put(AbstractMap.java:218)
       at com.package.MyView.method2(MyView.java:108)
       at com.package.MyParentView.method1(MyParentView.java:1278)

【问题讨论】:

    标签: java kotlin exception crash


    【解决方案1】:

    我不知道这是否是这里发生的事情,但我们不应该真的像这样将只读类型转换为可变类型。如果getProductMap() 的返回类型是Map,而不是MutableMap,那么这可能是有原因的,我们不应该尝试使用它,因为它是可变的。

    例如,buildList(): List 实用程序实际上返回一个实现了MutableList 的列表,但实际上是只读的,当我们尝试修改它时会抛出异常。同样,从 Collections.unmodifiableMap() 这样的实用程序返回的集合可以转换为可变的。

    我认为您在这里真正需要做的是在地图中创建数据的可变副本:

    binding.myView.getProductMap().toMutableMap()
    

    或者,如果getProductMap() 返回可为空:

    binding.myView.getProductMap()?.toMutableMap() ?: mutableMapOf()
    

    附带说明,您的代码对我来说似乎很奇怪。如果它是可变的,它使用源映射的内容,但如果不是,它会忽略它的内容。

    【讨论】:

      【解决方案2】:

      我认为这里的问题是 MutableMapmapped type:Kotlin 编译器知道 MapMutableMap 之间的区别,但它们都编译为 @987654323 Java* 字节码中的@。这是因为底层的 Java 类不区分可变集合和不可变集合。它们对两者使用相同的接口,不可变的实现只需抛出UnsupportedOperationException

      所以在这种情况下,as? 安全转换不会做你想做的事情:它只有效地检查对象是否是 Map,而不是它是否可变。 (我不了解 Android,但如果将 getProductMap() 定义为返回 Map,则归结为简单的空检查。)

      有几种方法可以解决此问题,具体取决于您的需要,例如:

      • 如果您碰巧知道您期望的具体的可变类型(例如ArrayList),那么您可以转换为那个类型。因为ArrayLists 总是可变的,所以put() 应该是安全的;但它不会做任何其他类型的地图提供。

      • 您可以将UnsupportedOperationException 困在try...catch 块中。这样可以避免错误,但如果提供了不可变映射,则什么也不做。

      • 您可以使用toMutableMap() 从给定的映射创建一个可变映射。这将始终更新地图 - 但它可能是视图未使用的私有地图。


      (* 堆栈跟踪显示这个问题是关于 Kotlin/JVM。  在其他平台上您可能会得到不同的结果。)

      【讨论】:

        猜你喜欢
        • 2014-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-24
        • 2018-01-24
        相关资源
        最近更新 更多