Kotlin 中的集合(List中没有了addAll())

为什么讲这个呢,集合还需要再老生常谈吗?,作为一个从java转向kotlin的人来说,集合还不是手到擒来。这里主要讲讲二者之间使用的区别,避免采坑。下面我们从实际案例入手:

想必大多数Android 开发者都有遇到过分页加载列表的需求吧,比如我们会写一个添加数据的代码

private List<MessageItem> list = null;

public MessageAdapter(List<MessageItem> list) {
    this.list = list;
}

public void appendData(List<MessageItem> list) {//必须是追加
    this.list.addAll(list);
    notifyDataSetChanged();
}

复制代码

使用java 编写 it work fine

但是使用kotlin编写的时候,按照我们以前的习惯我们往往会这么写

class MessageAdapter(var list: List<MessageItem>) {
    
    fun appendData(list: List<MessageItem>) {
        this.list.addAll(list)
        notifyDataSetChanged()
    }
}
复制代码

不好意思,直接报错,说没有这个方法,点击查看源码如下

/**
 * A generic ordered collection of elements. Methods in this interface support only read-only access to the list;
 * read/write access is supported through the [MutableList] interface.
 * @param E the type of elements contained in the list. The list is covariant on its element type.
 */
public interface List<out E> : Collection<E> {
    // Query Operations
    override val size: Int

    override fun isEmpty(): Boolean
    override fun contains(element: @UnsafeVariance E): Boolean
    override fun iterator(): Iterator<E>

    // Bulk Operations
    override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean

    // Positional Access Operations
    /**
     * Returns the element at the specified index in the list.
     */
    public operator fun get(index: Int): E

    // Search Operations
    /**
     * Returns the index of the first occurrence of the specified element in the list, or -1 if the specified
     * element is not contained in the list.
     */
    public fun indexOf(element: @UnsafeVariance E): Int

    /**
     * Returns the index of the last occurrence of the specified element in the list, or -1 if the specified
     * element is not contained in the list.
     */
    public fun lastIndexOf(element: @UnsafeVariance E): Int

    // List Iterators
    /**
     * Returns a list iterator over the elements in this list (in proper sequence).
     */
    public fun listIterator(): ListIterator<E>

    /**
     * Returns a list iterator over the elements in this list (in proper sequence), starting at the specified [index].
     */
    public fun listIterator(index: Int): ListIterator<E>

    // View
    /**
     * Returns a view of the portion of this list between the specified [fromIndex] (inclusive) and [toIndex] (exclusive).
     * The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
     *
     * Structural changes in the base list make the behavior of the view undefined.
     */
    public fun subList(fromIndex: Int, toIndex: Int): List<E>
}
复制代码

确实没有addAll,同样也没有add的方法。通过看注释,明白了,kotlin中的List是只支持读操作,是immutable,不支持写操作,如果想支持写操作,请使用MutableList,我们常用的ArrayList就是实现了MutableList 接口。

/**
 * A generic ordered collection of elements that supports adding and removing elements.
 * @param E the type of elements contained in the list. The mutable list is invariant on its element type.
 */
public interface MutableList<E> : List<E>, MutableCollection<E> {
    // Modification Operations
    /**
     * Adds the specified element to the end of this list.
     *
     * @return `true` because the list is always modified as the result of this operation.
     */
    override fun add(element: E): Boolean

    override fun remove(element: E): Boolean

    // Bulk Modification Operations
    /**
     * Adds all of the elements of the specified collection to the end of this list.
     *
     * The elements are appended in the order they appear in the [elements] collection.
     *
     * @return `true` if the list was changed as the result of the operation.
     */
    override fun addAll(elements: Collection<E>): Boolean

    /**
     * Inserts all of the elements of the specified collection [elements] into this list at the specified [index].
     *
     * @return `true` if the list was changed as the result of the operation.
     */
    public fun addAll(index: Int, elements: Collection<E>): Boolean

    override fun removeAll(elements: Collection<E>): Boolean
    override fun retainAll(elements: Collection<E>): Boolean
    override fun clear(): Unit

    // Positional Access Operations
    /**
     * Replaces the element at the specified position in this list with the specified element.
     *
     * @return the element previously at the specified position.
     */
    public operator fun set(index: Int, element: E): E

    /**
     * Inserts an element into the list at the specified [index].
     */
    public fun add(index: Int, element: E): Unit

    /**
     * Removes an element at the specified [index] from the list.
     *
     * @return the element that has been removed.
     */
    public fun removeAt(index: Int): E

    // List Iterators
    override fun listIterator(): MutableListIterator<E>

    override fun listIterator(index: Int): MutableListIterator<E>

    // View
    override fun subList(fromIndex: Int, toIndex: Int): MutableList<E>
}

复制代码

一看,果然支持各种add还有remove方法。上面的问题应该比较清晰了吧。现在我们再系统的了解一下Kotlin中的集合

集合:List、Set、Map

与大多数语言不同,Kotlin 区分可变集合与不可变集合(lists、sets、maps 等)。精确控制什么时候集合可编辑有助于消除 bug 以及设计良好的 API。

预先了解一个可变集合的只读 视图 与一个真正的不可变集合之间的区别是很重要的。它们都容易创建,但类型系统不能表达它们的差别,所以由你来跟踪(是否相关)。

Kotlin 的 List 类型是一个提供只读操作如 size、get等的接口。与 Java 类似,它继承自 Collection 进而继承自 Iterable。改变 list 的方法是由 MutableList 加入的。这一模式同样适用于 Set/MutableSet 及 Map<K, out V>/MutableMap<K, V>。

我们可以看下 list 及 set 类型的基本用法:

val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
val readOnlyView: List<Int> = numbers
println(numbers)        // 输出 "[1, 2, 3]"
numbers.add(4)
println(readOnlyView)   // 输出 "[1, 2, 3, 4]"
readOnlyView.clear()    // -> 不能编译
​
val strings = hashSetOf("a", "b", "c", "c")
assert(strings.size == 3)
复制代码

Kotlin 没有专门的语法结构创建 list 或 set。 要用标准库的方法,如 listOf()、 mutableListOf()、 setOf()、 mutableSetOf()。 在非性能关键代码中创建 map 可以用一个简单的惯用法来完成:mapOf(a to b, c to d)。

注意上面的 readOnlyView 变量(译者注:与对应可变集合变量 numbers)指向相同的底层 list 并会随之改变。 如果一个 list 只存在只读引用,我们可以考虑该集合完全不可变。创建一个这样的集合的一个简单方式如下:

val items = listOf(1, 2, 3) 目前 listOf 方法是使用 singletonList 实现的,但是未来可以利用它们知道自己不能变的事实,返回更节约内存的完全不可变的集合类型。

注意这些类型是协变的。这意味着,你可以把一个 List 赋值给 List 假定 Rectangle 继承自 Shape(集合类型与元素类型具有相同的继承关系)。对于可变集合类型这是不允许的,因为这将导致运行时故障:你可能向 List 中添加一个 Circle,而在程序的其他地方创建了一个其中含有 Circle 的 List`。

有时你想给调用者返回一个集合在某个特定时间的一个快照, 一个保证不会变的:

class Controller {
    private val _items = mutableListOf<String>()
    val items: List<String> get() = _items.toList()
}
复制代码

这个 toList 扩展方法只是复制列表项,因此返回的 list 保证永远不会改变。

List 与 set 有很多有用的扩展方法值得熟悉:

val items = listOf(1, 2, 3, 4)
items.first() == 1
items.last() == 4
items.filter { it % 2 == 0 }   // 返回 [2, 4]
​
val rwList = mutableListOf(1, 2, 3)
rwList.requireNoNulls()        // 返回 [1, 2, 3]
if (rwList.none { it > 6 }) println("No items above 6")  // 输出“No items above 6”
val item = rwList.firstOrNull()
复制代码

…… 以及所有你所期望的实用工具,例如 sort、zip、fold、reduce 等等。

非常值得注意的是,对只读集合返回修改后的集合的操作(例如 +、 filter、 drop 等)并不会以原子方式创建其结果,因此如果没有合适的同步机制,在不同的线程中使用其结果是不安全的。

Map 遵循同样模式。它们可以容易地实例化与访问,像这样:


val readWriteMap = hashMapOf("foo" to 1, "bar" to 2)
println(readWriteMap["foo"])  // 输出“1”
val snapshot: Map<String, Int> = HashMap(readWriteMap)
复制代码
参考

www.kotlincn.net/docs/refere…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值