Kotlin 1.0 在标准库中不会有不可变集合。但是,它确实具有只读和可变的接口。没有什么能阻止您使用第三方不可变集合库。
Kotlin 的List 接口中的方法“仅支持对列表的只读访问”,而其MutableList 接口中的方法支持“添加和删除元素”。然而,这两者都只是接口。
Kotlin 的 List 接口在编译时强制执行只读访问,而不是像 java.util.Collections.unmodifiableList(java.util.List) 那样将此类检查推迟到运行时进行(“返回指定列表的不可修改视图... [where] 尝试修改返回的列表...导致UnsupportedOperationException。” 它不强制执行不变性。
考虑以下 Kotlin 代码:
import com.google.common.collect.ImmutableList
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
fun main(args: Array<String>) {
val readOnlyList: List<Int> = arrayListOf(1, 2, 3)
val mutableList: MutableList<Int> = readOnlyList as MutableList<Int>
val immutableList: ImmutableList<Int> = ImmutableList.copyOf(readOnlyList)
assertEquals(readOnlyList, mutableList)
assertEquals(mutableList, immutableList)
// readOnlyList.add(4) // Kotlin: Unresolved reference: add
mutableList.add(4)
assertFailsWith(UnsupportedOperationException::class) { immutableList.add(4) }
assertEquals(readOnlyList, mutableList)
assertEquals(mutableList, immutableList)
}
注意readOnlyList 是List 和add 等方法无法解析(也不会编译),mutableList 可以自然变异,add on immutableList(来自 Google Guava) 也可以在编译时解析,但在运行时抛出异常。
除了最后一个导致Exception in thread "main" java.lang.AssertionError: Expected <[1, 2, 3, 4]>, actual <[1, 2, 3]>. 的断言之外,所有上述断言都通过了,即我们成功地改变了一个只读的List!
请注意,使用 listOf(...) 而不是 arrayListOf(...) 返回一个有效的不可变列表,因为您不能将其转换为任何可变列表类型。但是,将List 接口用于变量并不会阻止将MutableList 分配给它(MutableList<E> 扩展List<E>)。
最后,请注意 Kotlin(以及 Java)中的接口不能强制不变性,因为它“不能存储状态”(参见 Interfaces)。因此,如果您想要一个不可变的集合,您需要使用类似于 Google Guava 提供的集合。
另见ImmutableCollectionsExplained · google/guava Wiki · GitHub