一、标准函数
Kotlin的标准函数有很多,先学习常用的with、run、apply三个。
还有let标准函数,主要是配合 ?. 操作符进行判空处理,以保证线程安全。
标准函数with:
with函数接收两个参数:
第一个参数可以是任意类型的对象。
第二个参数是一个Lambda表达式,表达式中提供参数对象的上下文,即参数对象所在的场景,并使用Lambda表达式中的最后一行作为返回值。
使用格式为:
val res = with(obj){
//obj的上下文,要做的事
"value" //with的返回值
}
具体使用场景:当我们需要连续调用同一个对象的多种方法时,可以使代码更加简洁。例如,正常些一个吃水果的代码:
fun main() {
val list = mutableListOf<String>("Apple", "Banana", "Orange", "Pear", "Grape")
val builder = StringBuilder()
builder.append("Start eating fruits:\n")
for (fruit in list) {
builder.append(fruit).append('\n')
}
builder.append("You have eat all fruits!")
val res = builder.toString()
println(res)
}
代码中,我们连续调用了builder对象的很多函数方法,可以考虑使用with来进行简化,简化代码:
val res2 = with(builder) {
append("Start eating fruits:\n")
for (fruit in list) {
append(fruit).append('\n')
}
append("You have eat all fruits!")
toString()
}
println(res2)
根据with函数的使用格式,分析可知:
给with传入了一个StringBuilder对象,接下来整个Lambda表达式的上下文就是这个StringBuilder对象,这个builder对象会以 this对象形式 被传入到Lambda表达式,就不需要像之前builder.append()这样进行操作,直接调用append函数即可,其它的函数像toString()类似,都不需要对象进行调用。
进一步简化了代码。
标准函数run:
run()函数和with()函数区别不大,with()函数需要传入一个参数,然后以这个参数作为上下文进行操作。run()函数不需要传入参数,但是他需要在一个对象的基础上进行操作,他的使用格式如下:
val res = obj.run{
//obj的上下文
"value" //返回结果
}
从使用格式上看,与with()函数区别不大,Lambda表达式内的写法两者具有一致性。
使用run函数来更改上述吃水果的代码如下:
val res3 = builder.run {
append("Start eating fruits:\n")
for (fruit in list) {
append(fruit).append('\n')
}
append("You have eat all fruits!")
toString()
}
println(res3)
只是将调用with函数并传入StringBuilder对象改成了调用StringBuilder对象的run方法,其它代码保持不变。
标准函数apply:
apply()函数和run()函数相似,都不需要传入参数,都需要在某个函数上调用,并且只接收一个lambda表达式,也会在Lambda表达式中提供该对象的上下文。但是apply()函数不返回值,而是会自动返回该对象本身。apply()函数的使用格式如下:
val res = obj.apply{
//obj的上下文
}
//res == obj
使用apply()函数来更改上述吃水果代码如下:
val res4 = builder.apply {
append("Start eating fruits:\n")
for (fruit in list) {
append(fruit).append('\n')
}
append("You have eat all fruits!")
}
println(res4.toString())
想起之前在向intent中传递数据的代码,可以简化更改为:
val intent = Intent(context, SecondActivity::class.java).apply {
putExtra("data1", param1)
putExtra("data2", param2)
}
由于intent并不需要返回值,这里使用apply()函数来进行简化。
二、静态方法
Kotlin不同于java,java中定义静态方法,一般会在类中,使用static关键字来定义静态方法,使得该静态方法能够在不创建类的实例对象时,可以直接通过类名调用。例如:
public class Util {
public static void doSomeThing() {
System.out.println("Let's do something!");
}
}
这就是一个简单的工具类,工具类没有创建实例对象的必要,而且全局通用。
在Kotlin中,定义一个工具类,一般使用单例类来进行创建,上述代码在Kotlin中变为:
object Unit{
fun doSomeThing() {
println("Let's do something!")
}
}
将Unit定义为object类型,声明它是单例类。
这虽然不是静态方法,但是仍旧可以使用Unit.doSomeThing()来调用,和静态方法类似。
但是,使用这种方法,这样会导致这个类的所有方法都是工具类,当我们只想让类的某一个函数成为静态方法时,需要使用 companion object 方法。这相当于在类中创建了一个伴生类,而Kotlin会保证该类中只有这一个伴生类。代码如下:
class Unit{
fun doAction() {
println("do action!")
}
companion object{
fun doSomeThing() {
println("Let's do someThing!")
}
}
}
这里声明了Unit是普通class类,然后使用companion object创建了该类的伴生类,可直接通过该类名调用伴生类中的函数,即 Unit.doSomeThing()。
单例类和companion object都只是在语法的形式上模仿了静态方法的调用方式,实际上它们都不是真正的静态方法。因此如果你在Java代码中以静态方法的形式去调用这些方法的话,你会发现这些方法并不存在。
Kotlin为构建静态方法提供了两种方式:注解和顶层
注解:
如果我们给刚才的单例类或companion object中的方法加上@JvmStatic注解,那么Kotlin编译器就会将这些方法编译成真正的静态方法,例如;
class Unit{
fun doAction() {
println("do action!")
}
companion object{
@JvmStatic
fun doSomeThing() {
println("Let's do someThing!")
}
}
}
这样doSomeThing() 就成了静态方法。那么现在不管是在Kotlin中还是在Java中,都可以使用Util.doAction2()的写法来调用了。
顶层:
顶层方法指的是那些没有定义在任何类中的方法,比如我们编写的main()方法。Kotlin编译器会将所有的顶层方法全部编译成静态方法,因此只要你定义了一个顶层方法,那么它就一定是静态方法。
重新创建一个空的Kotlin文件,例如叫做TopFun.kt,文件中没有任何类,只有fun 定义的函数,这就是顶层方法。这个文件中的所有方法都是静态方法,可以全局调用。
但如果是在Java代码中调用,你会发现是找不到使用顶层方法定义的这些静态方法的,因为Java中没有顶层方法这个概念,所有的方法必须定义在类中。
我们刚才创建的Kotlin文件名叫作TopFun.kt,于是Kotlin编译器会自动创建一个叫作TopFunkt的Java类,其中的方法就是以静态方法的形式定义在TopFunkt类里面的,因此在Java中直接使用TopFunkt.fun()的写法来调用就可以了。