一、為了更友善調用
一個函數定義如下:
/**
* 實作輸入一個集合,如1,2,3 通過這個方法列印出 (1;2;3)
*/
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()
}
調用:
joinToString(collection, ";", "(", ")")
命名參數
可以發現調用時可讀性非常的差,如果不去查源碼函數聲明很難确定每個參數的含義,對于很多個Boolean類型的參數的函數更為明顯。
未解決這一問題,Kotlin可以顯式的标明參數名稱
joinToString(collection, separator = ";", prefix = "(", postfix = ")")
注意:
- 重命名函數的參數時要使用Rename處理,不能手動修改。
- 調用Java函數時不能采用命名參數的方式
預設參數值
Java中一個普遍存在的問題是,一些類的重載方法是在是太多了。為了相容性,導緻重複。
在Kotlin中可以在聲明函數時指定參數的預設值,這樣可以避免一部分的重複。
改進一下之前的函數
fun <T> joinToString(collection: Collection<T>,//輸入集合
separator: String = ";",//分隔符
prefix: String = "(",//字首
postfix: String = ")"//字尾
): String
調用結果
joinToString(collection, ";", "(", ")")
joinToString(collection, ";", "(")
joinToString(collection, ";")
joinToString(collection)
//上面幾種方式結果相同
消除頂層
如Java中的Util類,其中有靜态變量和靜态方法,使用類名點調用。
Kotlin中不需要在檔案中建立了類,直接寫方法或靜态變量即可
二、擴充函數和屬性
Kotlin可以為任何類添加成員函數
fun String.qit(): String return "1"
為String這個類添加了qit()函數,之後任何String類型的變量都會擁有這個函數
導入擴充函數
對于一個定義的擴充函數,他并不會自動的在整個項目中生效。為了避免偶然性的命名沖突,和其他函數一樣,使用它需要進行導入。
import 包名.qit
//也可用*
import 包名.*
//還可以使用as來修改名稱
import 包名.qit as tian
val c = "x".tian()
關鍵字as是解決命名沖突的唯一方式
注意:
- 擴充函數相當于靜态函數,不能被重寫
擴充屬性
//聲明一個擴充屬性
val String.mVal: String
get() = "2"
//聲明一個可變的擴充屬性
var StringBuilder.mVar: String
get() = "2"
set(value) {
this.setCharAt(1, '1')
}
三、處理集合:可變參數、中綴調用和庫的支援
可變參數
val list = listOf(1, 2, 3)
//可以發現建立List時可以傳任意數量的參數進去
//函數在庫中的聲明如下
fun <T> listOf(vararg value: T): List<T> {
...
}
vararg修飾符如同Java中三個點,不同的是當傳入的參數包裝在數組中時,Java可以直接傳入數組,而Kotlin要求解包裝,隻需在數組前加
*
即可
fun main(args:Array<String>){
val list = listOf("string1",*args)
}
中綴調用
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
這行代碼中的
to
是一種特殊函數調用,叫中綴調用,放在目标對象名稱和參數之間。中綴調用可以與隻有一個參數的函數一起使用,無論是普通函數還是擴充函數。要允許使用中綴符号調用函數,需要使用infix修飾符标記。
下面是一個簡版的to函數聲明:
infix fun Any.to(other: Any) = Pair(this, other)//忽略泛型
使用
to
可以生成
Pair對象
val (number, name) = 1 to "one"//解構聲明
四、局部函數和擴充
為減少重複代碼,Kotlin可以再函數中聲明嵌套的函數
class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {
if (user.name.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty Name")
if (user.name.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty Address")
}
這段代碼中重複代碼很少,但如果字段很多而且全面的驗證每一個字段的特殊情況,那就很麻煩了,使用局部函數之後可以這樣:
class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {
fun validate(user: User, value: String, fieldName: String) {
if (value.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName")
}
validate(user,user.name,"Name")
validate(user,user.address,"Address")
}
因為局部函數可以通路函數中所有變量,是以可以去掉局部的User參數
class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName")
}
validate(user.name, "Name")
validate(user.address, "Address")
}
提取成為User的擴充函數
class User(val id: Int, val name: String, val address: String)
fun User.validateBeforeSave() {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) throw IllegalArgumentException("Can't save user $id: empty $fieldName")
}
validate(name, "Name")
validate(address, "Address")
}
fun saveUser(user: User) {
user.validateBeforeSave()
}