kotlin高阶函数let、with、apply、run、also使用场景
let、with、apply、run、also这几个高阶函数非常相似,看定义也非常简单,初学kotlin时要么不记得使用它们,要么不知道选用哪个函数。
标准库之所以设计这些高阶函数,必定有需求和使用场景,本文讨论几个常见的使用场景。解决那些习惯Java语言的程序员们,初次使用kotlin造成困扰。
1. let
1.1 经常和?.操作符号联合使用,替代IF判断
var name:String? = null
var map = HashMap()
// name是可变变量,IF 条件判断不等于空,对于编译器来讲name还是可空变量,所以必须先赋值到val变量
val theName = name
if(theName !=null){
//此时theName是不可空变量
map[theName] = "OK"
}
// 使用?.let方法简化上面的代码
name?.let{
map[it] = "OK"
}
2. apply
2.1 创建对象并初始化设置
val map = HashMap()
map["name1"] = 18
map["name2"] = 18
// 使用apply
val map = HashMap().apply{
this["name1"] = 18
this["name2"] = 18
}
// 如果对象创建后立即作为参数,那么避免一个变量名
fun processUser(user:User)
processUser(User().apply{
this.name = "jimi"
this.age = 18
})
3. run
run函数有两种:一个是全局函数、一个是扩展函数
3.1 全局函数run 替代 java中 { } 代码作用域
java代码作用域有很多好处,比如避免临时变量名作用域过长,代码复制风险等,kotlin语法层面不支持代码作用域,可以通过run函数替代
fun logic(){
run{
val user = User()
user.xxxx
//....
addUser(user)
}
run{
val user = User()
user.yyyy
//....
addUser(user)
}
}
// 变量名user可以重复使用,避免user1、user2这种变量命名,容易在复制代码过程中造成错误
fun logic(){
val user1 = User()
user1.xxxx
//....
addUser(user1)
val user2 = User()
user1.yyyy // 第二段代码和第一段类似,通常通过复制来修改,但是常常忘记修改user1为user2,造成bug
//....
addUser(user2)
}
当然作用域还有其他语义更为明确等其他优势。
另外run也能把最好一行作为返回值,避免专门定义一个函数
val user = run{
val r1 = Role()
//.....
User(r1,...)
}
3.2 函数懒得定义返回类型
spring mvc 中Controller中对应RequestMapping的函数是定义可以省略返回类型定义,有时候比较方便
@GetMapping("/user/list")
fun list(): List{
return service.findUsers()
}
// 简写成
@GetMapping("/user/list")
fun list() = run {
service.findUsers()
}
4 also
5.1
Java中经常使用(line=reader.readLine())!=null这种写法,是由于赋值语句可以作为表达式才可以这么写。
但是kotlin的赋值语句不能作为表达式,所以刚开始使用kotlin会不习惯
public void test(BufferedReader reader) throws IOException {
String line;
while ( (line=reader.readLine())!=null ){
System.out.println(line);
}
}
在kotlin中
fun test(reader: BufferedReader) {
var line: String?
while (reader.readLine().also { line = it } != null) {
println(line)
}
}
also 通过it访问当前变量,并且整体返回自己。所以可以模拟赋值语句当做表达式的效果。
虽然apply也能做类似的事情
while (reader.readLine().apply { line = this } != null)
会造成语义不清晰,可读性不强,this到底指的哪个对象?
5 with
5.1 消除对同一个变量多次引用
val service = Service()
service.setName("xxx")
service.doSome()
service.ddd()
service.sddd()
// 使用with修改为
with(service){
this.setName("xxx")
this.doSome()
this.ddd()
this.sddd()
}
// 进一步省略this
with(service){
setName("xxx")
doSome()
ddd()
sddd()
}