
前言
本篇博客為本人學習Kotlin 中所遇到的問題,如果哪里寫的不對,希望歐大佬幫忙指出,多謝。
1. 集合的基礎使用
kotlin 中的集合主要為:Array、List、Set、Map , Sequence
1.1 數(shù)組
val arr = arrayOf("1",2,3,4)
1.2 List
不可變集合 ( listOf() )
val arr = arrayOf("1","2",3,4,5)
val list1 = listOf(1,2,"3",4,"5") // 隨意創(chuàng)建
val list2 = listOf<String>("1","2","3","4","5") // 確定元素的值類型
val list3 = listOf(arr) // 可傳入一個數(shù)組
以下代碼是錯誤的。因為List<E>只能是不可變集合。而add、remove、clear等函數(shù)時MutableList中的函數(shù)
list1.add()
list1.remove
可變集合 ( mutableListOf )
val arr = arrayOf("1","2",3,4)
val mutableList1 = mutableListOf(1,2,3,4,"5") // 隨意創(chuàng)建
val mutableList2 = mutableListOf<String>("1","2","3","4","5") // 確定元素的值類型
val mutableList3 = mutableListOf(arr) // 可傳入一個數(shù)組
val mutableList : ArrayList<String> // 這里的ArrayList<>和Java里面的ArrayList一致
mutableList1.add("6") // 添加元素
mutableList1.add("7")
mutableList1.remove(1) // 刪除某一元素
1.3 Set
val set1 = setOf(1,2,"3","4","2",1,2,3,4,5)
val mutableSet1 = mutableSetOf(1,2,"3","4","2",1,2,3,4,5)
// 這里的HashSet<>和Java里面的HashSet<>一致
val mutableSet2 : HashSet<String>
// 輸出結(jié)果 : 1 2 3 4 2 3 4 5
??當我們看到輸出結(jié)果的時候 發(fā)現(xiàn)所有的重復 數(shù)據(jù)都沒有了,這里的特點也是kotlin和java 保持了一致。
1.4 Map
// 以鍵值對的形式出現(xiàn),鍵與值之間使用to
val map1 = mapOf("key1" to 2 , "key2" to 3)
val map2 = mapOf<Int,String>(1 to "value1" , 2 to "value2")
val mutableMap = mutableMapOf("key1" to 2 , "key1" to 3)
// 同Java中的HashMap
val hashMap = hashMapOf("key1" to 2 , "key1" to 3)
val map = val map1 = mapOf("key1" to 2 , "key1" to 3 ,
"key1" to "value1" , "key2" to "value2")
//輸出結(jié)果 key1 value1 , key2 value2
當我們的鍵存在重復時,集合會過濾掉之前重復的元素。value 只保留了最后一個元素。而過濾掉了之前key值相同的所有元素。
2 List 和 Sequence 選擇使用
??相信大多Android 開發(fā)者都理解集合和序列的區(qū)別,那么我們應該如何更好的使用這兩個?
總結(jié)List的使用場景:
- 量級比較小的集合元素(當數(shù)量比較少的時候 List 和 Sequence 的循環(huán)耗時相差無幾)
- 訪問索引元素 (Lists(集合) 是有索引的,Sequences(序列) 則必須逐項進行.其實和 java 中的 ArrayList 和 LinkedList 知識點差不多)
- 返回/傳遞給其他的函數(shù) (每次迭代Sequences(序列) 時,都會計算元素。Lists(集合) 中的元素只計算一次,然后存儲在內(nèi)存中。)
我們這里之舉一個例子通過耗時的循環(huán)來看下兩者區(qū)別
Kotlin
list.map { it *3 }
.filter { it % 2 == 0 }
.count { it < 10 }
Kotlin code
Object element$iv$iv;
int it;
while(var5.hasNext()) {
element$iv$iv = var5.next();
it = ((Number)element$iv$iv).intValue();
Integer var12 = it * 3;
destination$iv$iv.add(var12);
}
$receiver$iv = (Iterable)((List)destination$iv$iv);
destination$iv$iv = (Collection)(new ArrayList());
var5 = $receiver$iv.iterator();
while(var5.hasNext()) {
element$iv$iv = var5.next();
it = ((Number)element$iv$iv).intValue();
if (it % 2 == 0) {
destination$iv$iv.add(element$iv$iv);
}
}
$receiver$iv = (Iterable)((List)destination$iv$iv);
if (!($receiver$iv instanceof Collection) || !((Collection)$receiver$iv).isEmpty()) {
int count$iv = 0;
Iterator var13 = $receiver$iv.iterator();
while(var13.hasNext()) {
Object element$iv = var13.next();
int it = ((Number)element$iv).intValue();
if (it < 10) {
++count$iv;
}
}
}
??你會發(fā)現(xiàn)Kotlin編譯器會創(chuàng)建三個while循環(huán).而Sequences則只會存在一個循環(huán),所以在循環(huán)多的情況下 還是Sequences 比較快一點。
kotlin
val result = list.asSequence()
.map{ println("In Map"); it * 2 }
.filter { println("In Filter");it % 3 == 0 }
println("Before Average")
println(result.average())
Kotlin code
List list = CollectionsKt.listOf(new Integer[]{1, 2, 3, 4, 5, 6});
Sequence result = SequencesKt.filter(SequencesKt.map(CollectionsKt.asSequence((Iterable)list), (Function1)null.INSTANCE), (Function1)null.INSTANCE);
String var3 = "Before Average";
System.out.println(var3);
double var5 = SequencesKt.averageOfInt(result);
System.out.println(var5);
??序列(Sequences) 的秘訣在于它們是共享同一個迭代器(iterator) ---序列允許 map操作 轉(zhuǎn)換一個元素后,然后立馬可以將這個元素傳遞給 filter操作 ,而不是像集合(lists) 一樣等待所有的元素都循環(huán)完成了map操作后,用一個新的集合存儲起來,然后又遍歷循環(huán)從新的集合取出元素完成filter操作。
3. 操作符匯總
??下面對這6類操作符進行一一的講解,不過這里就不對他們的源碼進行分析。大多都存在于_Collections.kt這個文件中。下邊的測試代碼和運行結(jié)果 我都 將結(jié)果和 方法放在一起了 好對比。
3.1 元素操作符
- contains(元素) : 檢查集合中是否包含指定的元素,若存在則返回true,反之返回false
- elementAt(index) : 獲取對應下標的元素。若下標越界,會拋出IndexOutOfBoundsException(下標越界)異常,同get(index)一樣
- elementAtOrElse(index,{...}) : 獲取對應下標的元素。若下標越界,返回默認值,此默認值就是你傳入的下標的運算值
- elementAtOrNull(index) : 獲取對應下標的元素。若下標越界,返回null
- first() : 獲取第一個元素,若集合為空集合,這會拋出NoSuchElementException異常
- first{} : 獲取指定元素的第一個元素。若不滿足條件,則拋出NoSuchElementException異常
- firstOrNull() : 獲取第一個元素,若集合為空集合,返回null
- firstOrNull{} : 獲取指定元素的第一個元素。若不滿足條件,返回null
- getOrElse(index,{...}) : 同elementAtOrElse一樣
- getOrNull(index) : 同elementAtOrNull一樣
- last () : 同first()相反
- last {} : 同first{}相反
- lastOrNull{} : 同firstOrNull()相反
- lastOrNull() : 同firstOrNull{}相反
- indexOf(元素) : 返回指定元素的下標,若不存在,則返回-1
- indexOfFirst{...} : 返回第一個滿足條件元素的下標,若不存在,則返回-1
- indexOfLast{...} : 返回最后一個滿足條件元素的下標,若不存在,則返回-1
- single() : 若集合的長度等于0,則拋出NoSuchElementException異常,若等于1,則返回第一個元素。反之,則拋出IllegalArgumentException異常
- single{} : 找到集合中滿足條件的元素,若元素滿足條件,則返回該元素。否則會根據(jù)不同的條件,拋出異常。這個方法慎用
- singleOrNull() : 若集合的長度等于1,則返回第一個元素。否則,返回null
- singleOrNull{} : 找到集合中滿足條件的元素,若元素滿足條件,則返回該元素。否則返回null
- forEach{...} : 遍歷元素。一般用作元素的打印
- forEachIndexed{index,value} : 遍歷元素,可獲得集合中元素的下標。一般用作元素以及下標的打印
- componentX() : 這個函數(shù)在前面的章節(jié)中提過多次了。用于獲取元素。其中的X只能代表1..5。詳情可看下面的例子
eg:
val list = listOf("kotlin","Android","Java","PHP","Python","IOS")
println(list.contains("JS")) // false
println(list.elementAt(2)) // Java
println(list.elementAtOrElse(10,{it})) // 10
println(list.elementAtOrNull(10)) // null
println(list.get(2)) // Java
println(list.getOrElse(10,{it})) // 10
println(list.getOrNull(10)) // null
println(list.first()) // kotlin
println(list.first{ it == "Android" }) // Android
println(list.firstOrNull()) // kotlin
println(list.firstOrNull { it == "Android" }) // Android
println(list.last()) // IOS
println(list.last{ it == "Android" }) // Android
println(list.lastOrNull()) // IOS
println(list.lastOrNull { it == "Android" }) // Android
println(list.indexOf("Android")) // 1
println(list.indexOfFirst { it == "Android" }) // 1
println(list.indexOfLast { it == "Android" }) // 1
val list2 = listOf("list")
// 只有當集合只有一個元素時,才去用這個函數(shù),不然都會拋出異常。
println(list2.single()) // list
//當集合中的元素滿足條件時,才去用這個函數(shù),不然都會拋出異常。若滿足條件返回該元素
println(list2.single { it == "list" }) // list
// 只有當集合只有一個元素時,才去用這個函數(shù),不然都會返回null。
println(list2.singleOrNull()) // list
//當集合中的元素滿足條件時,才去用這個函數(shù),不然返回null。若滿足條件返回該元素
println(list2.singleOrNull { it == "list" }) // list
list.forEach { println(it) }
// kotlin
// Android
// Java
// PHP
// Python
// IOS
list.forEachIndexed { index, it -> println("index : $index \t value = $it") }
/**
index : 0 value = kotlin
index : 1 value = Android
index : 2 value = Java
index : 3 value = PHP
index : 4 value = Python
index : 5 value = IOS
**/
// 等價于`list[0] <=> list.get(0)`
println(list.component1()) // kotlin
....
// 等價于`list[4] <=> list.get(4)`
println(list.component5()) // Python
3.2 順序操作符
- reversed() : 反序。
- sorted() : 升序。
- sortedBy{} : 根據(jù)條件升序。把不滿足條件的放在前面,滿足條件的放在后面
- sortedDescending() : 降序。
- sortedByDescending{} : 根據(jù)條件降序。
eg:
val list1 = listOf(-1,-2,1,3,5,6,7,2,4)
// 反序
println(list1.reversed()) // [4, 2, 7, 6, 5, 3, 1, -2, -1]
// 升序
println(list1.sorted()) // [-2, -1, 1, 2, 3, 4, 5, 6, 7]
// 根據(jù)條件升序,即把不滿足條件的放在前面,滿足條件的放在后面
println(list1.sortedBy { it % 2 == 0}) // [-1, 1, 3, 5, 7, -2, 6, 2, 4]
// 降序
println(list1.sortedDescending()) // [7, 6, 5, 4, 3, 2, 1, -1, -2]
// 根據(jù)條件降序,和`sortedBy{}`相反
println(list1.sortedByDescending { it % 2 == 0 }) // [-2, 6, 2, 4, -1, 1, 3, 5, 7]
3.3 映射操作符
- map{...} : 把每個元素按照特定的方法進行轉(zhuǎn)換,組成新的集合。
- mapNotNull{...} : 同map{}函數(shù)的作用相同,過濾掉轉(zhuǎn)換之后為null的元素
- mapIndexed{index,result} : 把每個元素按照特定的方法進行轉(zhuǎn)換,只是其可以操作元素的下標(index),組成新的集合。
- mapIndexedNotNull{index,result} : 同mapIndexed{}函數(shù)的作用相同,只是過濾掉轉(zhuǎn)換之后為null的元素
- flatMap{...} : 根據(jù)條件合并兩個集合,組成新的集合。
- groupBy{...} : 分組。即根據(jù)條件把集合拆分為為一個Map<K,List<T>>類型的集合。
eg:
val list1 = listOf("kotlin","Android","Java","PHP","JavaScript")
println(list1.map { "str-".plus(it) })
//[str-kotlin, str-Android, str-Java, str-PHP, str-JavaScript]
println(list1.mapNotNull { "str-".plus(it) })
// [str-kotlin, str-Android, str-Java, str-PHP, str-JavaScript]
println(list1.mapIndexed { index, str ->
index.toString().plus("-").plus(str)
})
//[0-kotlin, 1-Android, 2-Java, 3-PHP, 4-JavaScript]
println(list1.mapIndexedNotNull { index, str ->
index.toString().plus("-").plus(str)
})
// [0-kotlin, 1-Android, 2-Java, 3-PHP, 4-JavaScript]
println( list1.flatMap { listOf(it,"new-".plus(it)) })
//[kotlin, new-kotlin, Android, new-Android, Java, new-Java, PHP, new-PHP, JavaScript, new-JavaScript]
println(list1.groupBy { if (it.startsWith("Java")) "big" else "latter" })
// {latter=[kotlin, Android, PHP], big=[Java, JavaScript]}
3.4 過濾操作符
- filter{...} : 把不滿足條件的元素過濾掉
- filterIndexed{...} : 和filter{}函數(shù)作用類似,可以操作集合中元素的下標
- filterNot{...} : 和filter{}函數(shù)的作用相反
- filterNotNull() : 過濾掉集合中為null的元素。
- take(num) : 返回集合中前num個元素組成的集合
- takeWhile{...} : 循環(huán)遍歷集合,從第一個元素開始遍歷集合,當?shù)谝粋€出現(xiàn)不滿足條件元素的時候,退出遍歷。然后把滿足條件所有元素組成的集合返回。
- takeLast(num) : 返回集合中后num個元素組成的集合
- takeLastWhile{...} : 循環(huán)遍歷集合,從最后一個元素開始遍歷集合,當?shù)谝粋€出現(xiàn)不滿足條件元素的時候,退出遍歷。然后把滿足條件所有元素組成的集合返回。
- drop(num) : 過濾集合中前num個元素
- dropWhile{...} : 相同條件下,和執(zhí)行takeWhile{...}函數(shù)后得到的結(jié)果相反
- dropLast(num) : 過濾集合中后num個元素
- dropLastWhile{...} : 相同條件下,和執(zhí)行takeLastWhile{...}函數(shù)后得到的結(jié)果相反
- distinct() : 去除重復元素
- distinctBy{...} : 根據(jù)操作元素后的結(jié)果去除重復元素
- slice : 過濾掉所有不滿足執(zhí)行下標的元素。
eg:
val list1 = listOf(-1,-3,1,3,5,6,7,2,4)
val list2 = listOf(1,3,4,5,null,6,null,10)
val list3 = listOf(1,1,5,2,2,6,3,3,7,4)
println(list1.filter { it > 1 }) // [3, 5, 6, 7, 2, 4]
println(list1.filterIndexed { index, result ->
index < 5 && result > 3
})
// [5]
println(list1.filterNot { it > 1 }) // [-1, -3, 1]
println(list2.filterNotNull()) // [1, 3, 4, 5, 6, 10]
println(list1.take(5)) // [-1, -3, 1, 3, 5]
println(list1.takeWhile { it < 5 }) // [-1, -3, 1, 3]
println(list1.takeLast(5)) // [5, 6, 7, 2, 4]
println(list1.takeLastWhile { it > 5 }) // []
println(list1.drop(5)) // [6, 7, 2, 4]
println(list1.dropWhile { it < 5 }) // [5, 6, 7, 2, 4]
println(list1.dropLast(5)) // [-1, -3, 1, 3]
println(list1.dropLastWhile { it > 5 }) // [-1, -3, 1, 3, 5, 6, 7, 2, 4]
println(list3.distinct()) // [1, 5, 2, 6, 3, 7, 4]
println(list3.distinctBy { it + 2 }) // [1, 5, 2, 6, 3, 7, 4]
println(list1.slice(listOf(1,3,5,7))) // [-3, 3, 6, 2]
println(list1.slice(IntRange(1,5))) // [-3, 1, 3, 5, 6]
3.5 生產(chǎn)操作符
- plus() : 合并兩個集合中的元素,組成一個新的集合。也可以使用符號+
- zip : 由兩個集合按照相同的下標組成一個新集合。該新集合的類型是:List<Pair>
- unzip : 和zip的作用相反。把一個類型為List<Pair>的集合拆分為兩個集合??聪旅娴睦?/li>
- partition : 判斷元素是否滿足條件把集合拆分為有兩個Pair組成的新集合
eg:
val list1 = listOf(1,2)
val list2 = listOf("kotlin","Android","Java")
println(list1.plus(list2)) // [1, 2, kotlin, Android, Java]
println(list1 + list2) // [1, 2, kotlin, Android, Java]
// 組成的新集合由元素少的原集合決定
println(list1.zip(list2)) // [(1, kotlin), (2, Android)]
// 組成的新集合由元素少的原集合決定
println(list1.zip(list2){
it1,it2-> it1.toString().plus("-").plus(it2)
}) // [1-kotlin, 2-Android]
val newList = listOf(Pair(1,"Kotlin"),Pair(2,"Android"),Pair(3,"Java"))
println(newList.unzip()) // ([1, 2, 3,], [Kotlin, Android, Java])
println(list2.partition { it.startsWith("Ja") }) // ([Java], [kotlin, Android])
3.6 統(tǒng)計操作符
- any() : 判斷是不是一個集合,若是,則在判斷集合是否為空,若為空則返回false,反之返回true,若不是集合,則返回hasNext
- any{...} : 判斷集合中是否存在滿足條件的元素。若存在則返回true,反之返回false
- all{...} : 判斷集合中的所有元素是否都滿足條件。若是則返回true,反之則返回false
- none() : 和any()函數(shù)的作用相反
- none{...} : 和all{...}函數(shù)的作用相反
- max() : 獲取集合中最大的元素,若為空元素集合,則返回null
- maxBy{...} : 獲取方法處理后返回結(jié)果最大值對應那個元素的初始值,如果沒有則返回null
- min() : 獲取集合中最小的元素,若為空元素集合,則返回null
- minBy{...} : 獲取方法處理后返回結(jié)果最小值對應那個元素的初始值,如果沒有則返回null
- sum() : 計算出集合元素累加的結(jié)果。
- sumBy{...} : 根據(jù)元素運算操作后的結(jié)果,然后根據(jù)這個結(jié)果計算出累加的值。
- sumByDouble{...} : 和sumBy{}相似,不過sumBy{}是操作Int類型數(shù)據(jù),而sumByDouble{}操作的是Double類型數(shù)據(jù)
- average() : 獲取平均數(shù)
- reduce{...} : 從集合中的第一項到最后一項的累計操作。
- reduceIndexed{...} : 和reduce{}作用相同,只是其可以操作元素的下標(index)
- reduceRight{...} : 從集合中的最后一項到第一項的累計操作。
- reduceRightIndexed{...} : 和reduceRight{}作用相同,只是其可以操作元素的下標(index)
- fold{...} : 和reduce{}類似,但是fold{}有一個初始值
- foldIndexed{...} : 和reduceIndexed{}類似,但是foldIndexed{}有一個初始值
- foldRight{...} : 和reduceRight{}類似,但是foldRight{}有一個初始值
- foldRightIndexed{...} : 和reduceRightIndexed{}類似,但是foldRightIndexed{}有一個初始值
eg:
val list1 = listOf(1,2,3,4)
println(list1.any()) // true
println(list1.any{it > 10}) // false
println(list1.all { it > 2 }) // false
println(list1.none()) // false
println(list1.none{ it > 2}) // false
println(list1.max()) // 4
println(list1.maxBy { it + 2 }) // 4
println(list1.min()) // 1
println(list1.minBy { it + 2 }) // 1
println(list1.sum()) // 10
println(list1.sumBy { it + 2 }) // 18
println(list1.sumByDouble { it.toDouble() }) // 10.0
println(list1.average()) // 2.5
println(list1.reduce { result, next -> result + next}) // 10
println(list1.reduceIndexed { index, result, next ->
index + result + next
}) // 16
println(list1.reduceRight { result, next -> result + next }) // 10
println(list1.reduceRightIndexed {index, result, next ->
index + result + next
}) // 13
println(list1.fold(3){result, next -> result + next}) // 13
println(list1.foldIndexed(3){index,result, next ->
index + result + next
}) // 19
println(list1.foldRight(3){result, next -> result + next}) // 13
println(list1.foldRightIndexed(3){index,result, next ->
index + result + next
}) // 19