為什麼講這個呢,集合還需要再老生常談嗎?,作為一個從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)
複製程式碼