Kotlin集合接口
Kotlin 集合概述
Kotlin 集合提供了对数据进行各种操作的便捷方式。它们实现了接口,因此可以操作不同类型的数据。例如,你可以编写一个函数,同时打印 Set
和 List
的所有元素。我们来看看这是如何实现的。
Iterable 接口
我们已经知道,Kotlin 中有两个通用接口:Iterable
和 MutableIterable
,它们提供了一系列用于处理元素序列的方法。
继承自 Iterable
的类拥有一组通用方法,例如:
-
iterator()
-
forEach()
-
contains()
-
count()
-
drop()
-
filter()
等。
而 MutableIterable
除了拥有 Iterable
的方法外,还支持迭代时移除元素的方法,例如:
-
remove()
-
removeAll()
。
值得注意的是,虽然 drop()
和 remove()
都可以“移除”元素,但它们的行为不同:
-
drop()
返回的是一个新的集合对象。 -
remove()
会直接修改原集合对象(前提是集合是可变的)。
还要注意:你只能使用同一个 iterator
对象遍历一次集合,如果想再遍历一次,就必须重新创建一个新的 iterator()
。
当然你也可以使用 for
循环或者 forEach()
来迭代集合。
Collection 接口结构
我们来看看 Kotlin 集合之间的继承关系:
-
Iterable<T>
←Collection<T>
←List<T>
或Set<T>
-
MutableIterable<T>
←MutableCollection<T>
←MutableList<T>
或MutableSet<T>
其中:
-
Collection<T>
是不可变集合的根接口,支持size
、get()
、find()
、filter()
、count()
等方法。 -
MutableCollection<T>
是可变集合的根接口,支持add()
、remove()
、drop()
、addAll()
等方法。
注意:虽然我们通常也将 Map
称作集合,但它并不继承自 Collection
或 Iterable
,因为它存储的是键值对而不是单个元素,所以它有自己独特的方法集合。
使用 Collection 接口举例
你可以通过三种方式遍历集合:
fun printAll(strings: Collection<String>) {for (str in strings) print("$str ")
}fun printAll(songs: Collection<String>) {songs.forEach { print("$it ") }
}fun printAll(songs: Collection<String>) {val songsIterator = songs.iterator()while (songsIterator.hasNext()) {print("${songsIterator.next()} ")}
}
示例:
val listOfSongs = listOf("Creep", "Idioteque", "Street Spirit", "Paranoid Android")
printAll(listOfSongs)
// 输出:Creep Idioteque Street Spirit Paranoid Android
所有集合都有一些通用的方法:
-
count()
:返回满足条件的元素数量。 -
drop()
:返回一个新的列表,其中不包含前 n 个元素。 -
containsAll()
:检查集合是否包含另一个集合中的所有元素,并返回 true 或 false。
常用方法示例:
fun countElements(strings: Collection<String>) = strings.count { it.matches("\\w+".toRegex()) }fun dropElements(songs: Collection<String>) = songs.drop(2).toSet()fun compareCollections(old: Collection<String>, new: Collection<String>) = old.containsAll(new)val setOfSongs = setOf("Creep", "Idioteque", "Street Spirit", "Paranoid Android")
val listOfSongs = listOf("Creep", "Idioteque", "Street Spirit", "Paranoid Android")println(countElements(setOfSongs)) // 输出:2
println(dropElements(listOfSongs)) // 输出:[Street Spirit, Paranoid Android]
println(compareCollections(listOfSongs, setOfSongs)) // 输出:true
更多集合操作方法
-
joinToString()
将集合作为带有特定分隔符的字符串返回。 -
find()
返回符合模式的第一个元素。 -
filter()
返回List
满足条件的元素。 -
minus()
返回不包含条件中指定的元素的集合。 -
random()
返回集合中的一个随机元素。
一些例子:
fun convertToString(strings: Collection<String>) = strings.joinToString(" | ")fun findElement(strings: Collection<String>) = strings.find { it.contains("I") }fun filterElements(strings: Collection<String>) = strings.filter { it.contains("t") }fun returnRandomElement(strings: Collection<String>) = strings.random()fun decreaseCollection(strings: Collection<String>) = strings.minus("Creep")
示例:
val listOfSongs = listOf("Creep", "Idioteque", "Street Spirit", "Paranoid Android")
val setOfSongs = setOf("Creep", "Idioteque", "Street Spirit", "Paranoid Android")println(convertToString(listOfSongs)) // Creep | Idioteque | Street Spirit | Paranoid Android
println(findElement(setOfSongs)) // Idioteque
println(filterElements(listOfSongs)) // [Idioteque, Street Spirit]
println(returnRandomElement(setOfSongs)) // 可能输出任意一个元素
println(decreaseCollection(setOfSongs)) // [Idioteque, Street Spirit, Paranoid Android]
注意:
drop()
和minus()
都不会修改原集合,而是返回一个新的集合对象。
MutableCollection 可变集合
MutableCollection
可以使用 Collection
的所有方法,还支持如下修改原集合的方法:
-
addAll()
:添加一整个集合。 -
add()
:添加单个元素。 -
clear()
:清空集合。 -
remove()
:移除元素的第一个出现位置。
fun addCollection(old: MutableCollection<String>, new: Collection<String>) {old.addAll(new)
}fun addNewElement(old: MutableCollection<String>) {old.add("Spectre")
}fun clearCollection(old: MutableCollection<String>) {old.clear()
}fun removeElement(old: MutableCollection<String>): Boolean {return old.remove("Creep")
}
示例:
val oldSongs = mutableSetOf("Creep", "Street Spirit")
val newSongs = listOf("Creep", "Street Spirit", "Paranoid Android")clearCollection(oldSongs)
println(oldSongs) // []addCollection(oldSongs, newSongs)
println(oldSongs) // [Creep, Street Spirit, Paranoid Android]addNewElement(oldSongs)
println(oldSongs) // [Creep, Street Spirit, Paranoid Android, Spectre]removeElement(oldSongs)
println(oldSongs) // [Street Spirit, Paranoid Android, Spectre]
println(removeElement(oldSongs)) // false,因为没有 "Creep" 了
retainAll()
retainAll()
方法会让集合只保留在另一个集合中也存在的元素:
fun retainAllFromCollection(old: MutableCollection<String>, new: Collection<String>) {old.retainAll(new)
}val oldSongs = mutableSetOf("Creep", "Street Spirit", "Paranoid Android")
val newSongs = listOf("Spectre", "Street Spirit")retainAllFromCollection(oldSongs, newSongs)
println(oldSongs) // [Street Spirit]
函数与集合的关系
你可以使用集合的接口类型(如 Collection
或 List
)作为函数的参数,以创建更通用的处理函数。例如:
fun processNumbers(list: List<Number>) {list.forEach { print("$it ") }
}val numbers1 = listOf(0, 12, 10)
val numbers2 = listOf(0.0, 12.0, 10.0)
val numbers3 = listOf(423324534536356, 4L, 56L)processNumbers(numbers1) // 0 12 10
processNumbers(numbers2) // 0.0 12.0 10.0
processNumbers(numbers3) // 423324534536356 4 56
但如果你尝试在 Number
类型上做加法,会出错:
fun processNumbers(list: List<Number>) {list.forEach { print(it + 1) } // ❌ 报错:未解析的引用
}
因为 Number
是抽象类,不支持加法。你可以先转换类型:
fun processNumbers(list: List<Number>) {list.forEach { print("${it.toChar()} ") }
}val numbers1 = listOf(41, 42, 43)
processNumbers(numbers1) // ) * +
总结
- Kotlin 中集合是接口,可以通用于多种集合类型。
Collection
和MutableCollection
提供了许多通用操作方法。Map
虽然被称为集合,但并不继承自Collection
。可以编写通用函数处理Set
、List
、MutableSet
、MutableList
等集合类型。drop()
和minus()
不改变原集合,而remove()
、add()
会修改原集合(前提是集合是可变的)。