数据类中的可变列表被初始化为 ImmutableCollections$ListN

问题描述 投票:0回答:1

考虑以下 Kotlin 代码:

data class CachedUserData(var contracts: MutableList<String>) {
    var localDateTime: LocalDateTime = LocalDateTime.now()
}

当我尝试通过自动生成的 getter 合约列表并从外部修改它时,我会抛出异常

java.lang.UnsupportedOperationException: null
。调查显示,在此类中,
contracts
字段被初始化为类型
ImmutableCollections$ListN

我可以通过添加以下数据修改功能来绕过这个问题:

    fun addContract(item: String) {
        val newList = mutableListOf(*contracts.toTypedArray());
        newList.add(item);
        contracts = newList;
    }

然后,该类构造之后的类型是

ImmutableCollections$ListN
,但通过此函数调用进行修改后,该类型将更改为
ArrayList
并保持这种状态。

这个特定类的实例是作为网络资源获取(普通 Java

List
)的结果而创建的,随后通过流传递到某些过滤器,然后由
.toList()
Java 收集器收集。

我的问题是:

  • 为什么初始类型设置为 ImmutableCollection,即使我试图强烈说服 Kotlin 我希望这个列表是可修改的?
  • 有没有一种方法可以使其最初变得可修改并使用简单的
    .getContracts().add(value);
    构造?
  • 有没有地方详细描述这种行为? IE。一些隐式集合转换为一些不可变的阴影类型?

编辑: 该类在项目的某些 Java 部分中实例化,并提供

List<String>
类型作为输入参数:

提前非常感谢!

kotlin collections immutability
1个回答
2
投票

Java 没有额外的类型来区分可变列表和不可变列表。所有列表,无论是可变的还是不可变的,都由

java.util.List
类型表示。在 Kotlin 中,
List
MutableList
都映射到 Java 中的
java.util.List
接口。请参阅映射表此处

即使你说你的类的构造函数在 Kotlin 中应该采用

MutableList
,但就 Java 而言,构造函数采用
java.util.List
。因此,Java 中的代码可以向其传递可变列表和不可变列表。

您说 Java 代码将

Stream.toList
调用的结果传递给构造函数,这就是问题 -
toList
旨在返回不可变列表:

返回的

List
不可修改;调用任何 mutator 方法总会导致
UnsupportedOperationException
被抛出。

您应该使用

Collectors.toCollection
来控制返回列表的类型,并传入 mutable 列表类型的供应商。

// e.g. replace .toList() with
.collect(Collectors.toCollection(ArrayList::new))

或者,您可以在

addContract
块中执行此操作,而不是在
init
中创建列表的可变副本:

data class CachedUserData(var contracts: MutableList<String>) {
    init {
        contracts = ArrayList(contracts)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.