Kotlin知识归纳(二) —— 让函数更好调用

2,754 阅读5分钟

函数参数之惑

        当一个函数拥有多个参数,且存在多个相同类型参数紧挨着的情况时,往往不太清楚传入参数的位置是否正确,且严重影响函数的可读性。需要调用者跳转到函数对应的地方,对参数和函数定义中的参数列表进行匹对。这将对函数调用者造成很大的麻烦和困扰。

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定义的函数时,可以显示标明参数的名称。这种参数叫命名参数。

        当指明一个参数的名称后,避免混淆,其他参数都要标明名称。(既然显式的标明名称,也就不需要按原本参数定义的顺序传入参数)

joinToString(array,prefix = "(",separator = ",", postfix = "]")

注意:

  • 既然显示的标明了参数名,也就意味着当参数名或方法名进行改变时,其显式标明的参数名或方法名也需要进行改变。这时可以使用Idea的Rename进行修改。(先选中方法名或参数名 -> Refactor -> Rename)
  • 当调用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中支持局部函数,所谓局部函数就是在方法中声明方法,内部方法可以获取到外部函数的参数和局部变量。可以将各个小方法定义为局部方法,即提供所需的简洁结构也无须额外的语法开销。

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知识归纳(十四) —— 反射