Kotlin知識歸納(二) —— 讓函式更好呼叫

大棋發表於2019-05-28

函式引數之惑

        當一個函式擁有多個引數,且存在多個相同型別引數緊挨著的情況時,往往不太清楚傳入引數的位置是否正確,且嚴重影響函式的可讀性。需要呼叫者跳轉到函式對應的地方,對引數和函式定義中的引數列表進行匹對。這將對函式呼叫者造成很大的麻煩和困擾。

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()
}
複製程式碼

        針對這種情況,或許可以依靠IDE進行優化。如:Idea早已對此進行了優化,在對函式填寫引數時,會將引數對應位置的引數名稱進行提示。

Kotlin知識歸納(二) —— 讓函式更好呼叫

命名引數

        Kotlin在語法層上對該情況進行優化,當呼叫一個Kotlin定義的函式時,可以顯示標明引數的名稱。這種引數叫命名引數。

        當指明一個引數的名稱後,避免混淆,其他引數都要標明名稱。(既然顯式的標明名稱,也就不需要按原本引數定義的順序傳入引數)

joinToString(array,prefix = "(",separator = ",", postfix = "]")
複製程式碼

注意:

  • 既然顯示的標明瞭引數名,也就意味著當引數名或方法名進行改變時,其顯式標明的引數名或方法名也需要進行改變。這時可以使用Idea的Rename進行修改。(先選中方法名或引數名 -> Refactor -> Rename)
    Kotlin知識歸納(二) —— 讓函式更好呼叫
  • 當呼叫Java定義的函式時,不能採用命名引數,因為Java8之前不能把引數名存在,class檔案中。而Kotlin需要與Java6相容。所以,編譯器不能識別出函式引數的名稱。

函式過載之禍

        在Java中,支援對函式進行過載。這就造成多個相同名稱的函式,且其引數間只有細微的差別。當呼叫省略部分引數的函式時,可能不清楚到底呼叫的是哪一個函式。(例如:Thread類擁有8個建構函式)

預設引數

        而Kotlin只需要指定引數的預設值,就可以有效避免建立多個過載函式。這種帶有預設值的函式引數叫做預設引數。再配合命名引數進行使用時,可以很方便的對指定引數進行賦值,從而實現過載。

fun <T> joinToString(collection: Collection<T>,
                          separator:String = ",",
                          prefix:String = "",
                          postfix:String = ""):String
複製程式碼

呼叫時只需要傳入具體的集合物件,函式會使用預設引數的預設值對其進行運算。

當然,按引數定義的順序,傳入對應的引數也完全沒有問題。

val string = joinToString(array)
//像以前傳遞字首,分割符和字尾也沒有問題
val string = joinToString(array,"(",",")
val string = joinToString(array,"(",",", "]")
//配合命名引數食用,效果更佳
val string = joinToString(array,separator = ";")
複製程式碼

@JvmOverloads 提高Kotlin與Java的互動性

        Java 中沒有預設引數的概念,當從Java中呼叫Kotlin的函式時,必須顯示地傳遞所有引數值。為了讓Java呼叫者能呼叫該方法的過載函式,可以用@JvmOverloads註解它。在編譯時,編譯器會從最後一個引數開始逐個省略,生成Java的過載函式。

Kotlin知識歸納(二) —— 讓函式更好呼叫

區域性函式

        程式猿都認為方法越小越好,相比縱向冗長的程式碼片段,將其按照職責切分成功能單一的小的區域性方法,最後組織起來呼叫是最好的。但很多時候分解出來的小方法之間並沒有什麼明確的關係,最後以一個包含許多小方法的類告終。

        Kotlin中支援區域性函式,所謂區域性函式就是在方法中宣告方法,內部方法可以獲取到外部函式的引數和區域性變數。可以將各個小方法定義為區域性方法,即提供所需的簡潔結構也無須額外的語法開銷。

data class Person(val age:String?,val name:String?)

fun daqi(person: Person){
    if (person.age == null){
        throw IllegalArgumentException()
    }
    if (person.name == null){
        throw IllegalArgumentException()
    }
    //正常操作

}
複製程式碼

轉換為區域性函式:

fun daqi(person: Person){
    //需要在頂層定義,不然函式未定義無法使用
    fun personFileIsEmpty(value:String?,fileName:String){
        if (value == null){
            throw IllegalArgumentException("$fileName is null")
        }
    }
    
    personFileIsEmpty(person.age,"age")
    personFileIsEmpty(person.name,"name")
    
    //正常操作
}
複製程式碼

        區域性函式的缺點是:區域性函式的不能宣告為內聯,並且擁有區域性函式的的函式也不能宣告為內聯。暫時沒有任何辦法避免這種函式的呼叫成本。

參考資料:

android Kotlin系列:

Kotlin知識歸納(一) —— 基礎語法

Kotlin知識歸納(二) —— 讓函式更好呼叫

Kotlin知識歸納(三) —— 頂層成員與擴充套件

Kotlin知識歸納(四) —— 介面和類

Kotlin知識歸納(五) —— Lambda

Kotlin知識歸納(六) —— 型別系統

Kotlin知識歸納(七) —— 集合

Kotlin知識歸納(八) —— 序列

Kotlin知識歸納(九) —— 約定

Kotlin知識歸納(十) —— 委託

Kotlin知識歸納(十一) —— 高階函式

Kotlin知識歸納(十二) —— 泛型

Kotlin知識歸納(十三) —— 註解

Kotlin知識歸納(十四) —— 反射

相關文章