1、在kotlin中創建集合
kotlin沒有自己專門的集合類,而是采用的java的集合類,不過書寫方式不一樣。
val set=hashSetOf(1,7,53) //對應hashset
val list=arrayListOf(1,7,53) //ArrayList
val map=hashMapOf(1 to "one",7 to "seven",53 to "fifty-three")//HashMap
不過kotlin有自己新增的方法:last(),max()集合中最后一個元素和最大的元素。
2、讓函數更好調用
java的集合都有一個默認的toString()實現,但是它的輸出格式是固定的。
val list=listOf(1,2,3)//listOf對應的是(Arrays內部類ArrayList)
println(list)
結果:[1,2,3]
上面的結果是固定格式的,默認實現了toString().
fun <T> joinToString(collection:Collection<T>,separator:String,prefix:String,postfix:String):String{
val result=StringBuilder(prefix)
for((index,element) in collection.withIndex()){
if(index>0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
val list=listOf(1,2,3)
println(joinToString(list,"; ","(",")"))
結果:(1;2;3)
當我們想要改變集合輸出格式的時候可以自定義,像上面這樣:逗號變分號。
2.1 命名參數
在上面的例子中,我們單看這一句joinToString(list,"; ","(",")")會發現我們必須要找到上面對應的函數聲明才能更好的理解我們寫的是啥。
為了解決這個問題,kotlin引出了命名參數:當調用一個kotlin自定義的函數時,可以顯式地標明一些參數的名稱。
joinToString(list,separator=";",prefix="(",postfix=")")
2.2 默認參數值
在聲明函數的時候,指定參數的默認值,可以避免創建重載的函數。
fun <T> joinToString(collection:Collection<T>,separator:String,prefix:String,postfix:String):String
當你調用的時候可以用所有參數來調用這個函數,也可以省略掉部分參數。
3、擴展函數和屬性
Kotlin 可以對一個類的屬性和方法進行擴展,且不需要繼承或使用 Decorator 模式。
擴展是一種靜態行為,對被擴展的類代碼本身不會造成任何影響。
3.1 導入和擴展函數
擴展函數可以在已有類中添加新的方法,不會對原類做修改.
擴展函數定義形式:
fun receiverType.functionName(params){
body
}
- receiverType:表示函數的接收者,也就是函數擴展的對象
- functionName:擴展函數的名稱
- params:擴展函數的參數,可以為NULL
以下實例擴展 User 類 :
class User(var name:String)
/**擴展函數**/
fun User.Print(){
print("用戶名 $name")
}
fun main(arg:Array<String>){
var user = User("Runoob")
user.Print()
}
實例執行輸出結果為:
用戶名 Runoob
下面代碼為 MutableList 添加一個swap 函數:
// 擴展函數 swap,調換不同位置的值
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // this 對應該列表
this[index1] = this[index2]
this[index2] = tmp
}
fun main(args: Array<String>) {
val l = mutableListOf(1, 2, 3)
// 位置 0 和 2 的值做了互換
l.swap(0, 2) // 'swap()' 函數內的 'this' 將指向 'l' 的值
println(l.toString())
}
實例執行輸出結果為:
[3, 2, 1]
3.2 不可重寫的擴展函數
擴展函數是靜態解析的,並不是接收者類型的虛擬成員,在調用擴展函數時,具體被調用的的是哪一個函數,由調用函數的的對象表達式來決定的,而不是動態的類型決定的:
open class C
class D: C()
fun C.foo() = "c" // 擴展函數 foo
fun D.foo() = "d" // 擴展函數 foo
fun printFoo(c: C) {
println(c.foo()) // 類型是 C 類
}
fun main(arg:Array<String>){
printFoo(D())
}
實例執行輸出結果為:
c
若擴展函數和成員函數一致,則使用該函數時,會優先使用成員函數。
class C {
fun foo() { println("成員函數") }
}
fun C.foo() { println("擴展函數") }
fun main(arg:Array<String>){
var c = C()
c.foo()
}
實例執行輸出結果為:
成員函數
3.3 擴展屬性
除了函數,Kotlin 也支持屬性對屬性進行擴展:
val <T> List<T>.lastIndex: Int
get() = size - 1
擴展屬性允許定義在類或者kotlin文件中,不允許定義在函數中。初始化屬性因為屬性沒有后端字段(backing field),所以不允許被初始化,只能由顯式提供的 getter/setter 定義。
val Foo.bar = 1 // 錯誤:擴展屬性不能有初始化器
擴展屬性只能被聲明為 val。
4、可變參數、中綴調用和庫的支持
4.1 擴展java集合的API
fun <T> List<T>.last():T//返回最后一個元素
fun Collection<Int>.max():Int//返回集合中的最大值
為什么kotlin用的是java的集合,卻能給它添加自己又增加的方法?
函數last和max都被聲明成了擴展函數。
4.2 可變參數:讓函數支持任意數量的參數
可變參數的關鍵字vararg,可以用來聲明一個函數將可能有任意數量的參數
fun listOf
kotlin庫中是這樣定義listOf()函數的,正因為這樣我們調用它時才可以傳遞任意個數的參數給它
kotlin和java的另一個區別是:當需要傳遞的參數已經包裝在數組中時,調用該函數的語法。
在java中可以按原樣傳遞數組,kotlin要求你顯式地解包數組。這個叫做展開運算符,在參數前面加*
fun main(args:Array<String>){
val list=listOf("args: ",*args)
println(list)
}
4.3 鍵值對的處理:中綴調用和重構聲明
val map=mapOf(1 to "one",7 to "seven",53 to "fifty-three")
這行代碼中的單詞to不是內置結構,而是一種特殊的函數調用,被稱為中綴調用。
重構聲明:
中綴調用可以與只有一個參數的函數一起使用,無論是普通的函數還是擴展函數。要允許使用中綴符合調用函數,需要使用infix修飾符來標記它。
infix fun Any.to(other:Any)=Pair(this,other)
我們可以直接用Pair的內容來初始化兩個變量。
val (number,name)=1 to "one"
這個功能稱為解構聲明。
5、字符串和正則表達式的處理
5.1 分割字符串
println("12.345-6.A".split("\\.|-".toRegex()))
結果:[12,345,6,A]
kotlin提供了一些名為split的,具有不同參數的重載的擴展函數。用來承載正則表達式的值需要一個Regex類型,而不是String。上面例子中就是使用擴展函數toRegex將字符串轉換為正則表達式。
但是對於一些簡單的情況,不需要使用正則表達式。kotlin中的split擴展函數的其他重載支持任意數量的純文本字符串分隔符:
println("12.345-6.A".split(".","-"))
[12,345,6,A]
5.2 正則表達式和三重引號的字符串
我們解析一個文件路徑:/Users/yole/kolin-book/chapter.doc
①使用String的擴展函數來解析文件路徑
fun parsePath(path:String){
val directory=path.substringBeforeLast("/")
val fullName=path.substringAfterLast("/")
val fileName=fullName.subStringBeforeLast(".")
val extension=fullName.subStringAfterLast(".")
println("Dir:$directory,name:$fileName,ext:$extension")
}
parsePath("/Users/yole/kolin-book/chapter.doc")
結果:Dir:Users/yole/kolin-book,name:chapter,ext:doc
②使用正則表達式來解析文件路徑
fun parsePath(path:String){
val regex="""(.+)/(.+)\.(.+)""".toRegex()
val matchResult=regex.matchEntire(path)
if(matchResult!=null){
val (directory,filename,extension)=matchResult.destructured
println("Dir:$directory,name:$fileName,ext:$extension")
}
}
三重引號字符串不需要對任何字符進行轉義。第一個(.+)包含最后一個斜線前的字串。第二個包含最后一個點前的字串,第三個包含剩余部分。
5.3 多行三重引號的字符串
三重引號字符串不僅可以避免轉義字符,而且它可以包含任意字符,包括換行符。而且它提供了一種簡單的方法把包含換行符的文本嵌入到程序中。
val kotlinLogo="""| //
.|//
.|/ \"""
println(kotlinLogo.trimMargin("."))
結果: | //
|//
|/ \