一、为了更方便调用
一个函数定义如下:
/**
* 实现输入一个集合,如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()
}