乐趣区

关于kotlin:Kotlin-标准函数和静态方法第一行代码-Kotlin-学习笔记

规范函数和静态方法

学完了 Kotlin 的基础知识而已,明天咱们来学习 Kotlin 的规范函数和静态方法。

规范函数 with、run 和 apply

Kotlin 的规范函数指的是 Standard.kt 文件中定义的函数,任何 Kotlin 代码都能够自在地调用所有的规范函数。

在 疾速入门 kotlin 编程 中,咱们曾经学习了 let 这个规范函数,它的次要作用就是配合 ?. 操作符来进行辅助判空解决,这里就不再赘述了。

with 规范函数

with 函数接管两个参数:第一个参数能够是一个任意类型的对象,第二个参数是一个 Lambda 表达式。with 函数会在 Lambda 表达式中提供第一个参数对象的上下文,并应用 Lambda 表达式中的最初一行代码作为返回值返回 。示例代码如下:

val result = with(obj) {
    // 这里是 obj 的上下文
    "value" // with 函数的返回值
}

那么这个函数有什么作用呢?它能够在间断调用同一个对象的多个办法时让代码变得更加精简,上面咱们来看一个具体的例子。

比方有一个水果列表,当初咱们想吃完所有水果,并将后果打印进去,就能够这样写:

val list = listOf("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("Ate all fruits.")
val result = builder.toString()
println(result)

仔细观察上述代码,你会发现咱们间断调用了很屡次 builder 对象的办法。其实这个时候就能够思考应用 with 函数来让代码变得更加精简,如下所示:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = with(StringBuilder()) {append("Start eating fruits.\n")
    for (fruit in list) {append(fruit).append("\n")
    }
    append("Ate all fruits.")
    toString()}
println(result)

这段代码乍一看可能有点迷惑性,其实很好了解。首先咱们给 with 函数的第一个参数传入了一个 StringBuilder 对象,那么接下来整个 Lambda 表达式的上下文就会是这个 StringBuilder 对象。于是咱们在 Lambda 表达式中就不必再像方才那样调用 builder.append() 和 builder.toString() 办法了,而是能够间接调用 append() 和 toString() 办法。Lambda 表达式的最初一行代码会作为 with 函数的返回值返回,最终咱们将后果打印进去。

run 规范函数

run 函数的用法和应用场景其实和 with 函数是十分相似的,只是略微做了一些语法改变而已。首先 run 函数通常不会间接调用,而是要在某个对象的根底上调用;其次 run 函数只接管一个 Lambda 参数,并且会在 Lambda 表达式中提供调用对象的上下文。其余方面和 with 函数是一样的,包含也会应用 Lambda 表达式中的最初一行代码作为返回值返回 。示例代码如下:

val result = obj.run {
    // 这里是 obj 的上下文
    "value" // run 函数的返回值
}

那么当初咱们就能够应用 run 函数来批改一下吃水果的这段代码,如下所示:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().run {append("Start eating fruits.\n")
    for (fruit in list) {append(fruit).append("\n")
    }
    append("Ate all fruits.")
    toString()}
println(result)

总体来说变动十分小,只是将调用 with 函数并传入 StringBuilder 对象改成了调用 StringBuilder 对象的 run 办法,其余都没有任何区别,这两段代码最终的执行后果是完全相同的。

apply 规范函数

apply 函数和 run 函数也是极其相似的,都要在某个对象上调用,并且只接管一个 Lambda 参数,也会在 Lambda 表达式中提供调用对象的上下文,然而 apply 函数无奈指定返回值,而是会主动返回调用对象自身 。示例代码如下:

val result = obj.apply {// 这里是 obj 的上下文}
// result == obj

那么当初咱们再应用 apply 函数来批改一下吃水果的这段代码,如下所示:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().apply {append("Start eating fruits.\n")
    for (fruit in list) {append(fruit).append("\n")
    }
    append("Ate all fruits.")
}
println(result.toString())

留神这里的代码变动,因为 apply 函数无奈指定返回值,只能返回调用对象自身,因而这里的 result 实际上是一个 StringBuilder 对象,所以咱们在最初打印的时候还要再调用它的 toString() 办法才行。这段代码的执行后果和后面两段依然是完全相同的,我就不再反复演示了。

这样咱们就将 Kotlin 中最罕用的几个规范函数学完了,你会发现其实 with、run 和 apply 这几个函数的用法和应用场景是十分相似的。在大多数状况下,它们能够互相转换,但你最好还是要把握它们之间的区别,以便在编程时可能作出最佳的抉择。

回忆一下刚刚在最佳实际环节编写的启动 Activity 的代码:

val intent = Intent(context, SecondActivity::class.java)
intent.putExtra("param1", "data1")
intent.putExtra("param2", "data2")
context.startActivity(intent)

这里每传递一个参数就要调用一次 intent.putExtra() 办法,如果要传递 10 个参数,那就得调用 10 次。对于这种状况,咱们就能够应用规范函数来对代码进行精简,如下所示:

val intent = Intent(context, SecondActivity::class.java).apply {putExtra("param1", "data1")
    putExtra("param2", "data2")    
}
context.startActivity(intent)

能够看到,因为 Lambda 表达式中的上下文就是 Intent 对象,所以咱们不再须要调用 intent.putExtra() 办法,而是间接调用 putExtra() 办法就能够了。传递的参数越多,这种写法的劣势也就越显著。

定义静态方法

静态方法在某些编程语言外面又叫作类办法,指的就是那种不须要创立实例就能调用的办法,所有支流的编程语言都会反对静态方法这个个性。

在 Java 中 定义一个静态方法非常简单,只须要在办法上申明一个 static 关键字就能够了,如下所示:

public class Util {public static void doAction() {System.out.println("do action");
    }
}

这是一个非常简单的工具类,上述代码中的 doAction() 办法就是一个静态方法。调用静态方法并不需要创立类的实例,而是能够间接以 Util.doAction() 这种写法来调用。因此静态方法非常适合用于编写一些工具类的性能,因为工具类通常没有创立实例的必要,根本是全局通用的。

然而和绝大多数支流编程语言不同的是,Kotlin 却极度弱化了静态方法这个概念,想要在 Kotlin 中定义一个静态方法反倒不是一件容易的事。

那么 Kotlin 为什么要这样设计呢?因为 Kotlin 提供了比静态方法更好用的语法个性,并且咱们在上一节中曾经学习过了,那就是单例类。

单例类

像工具类这种性能,在 Kotlin 中就十分举荐应用单例类的形式来实现,比方上述的 Util 工具类,如果应用 Kotlin 来实现的话就能够这样写:

object Util {fun doAction() {println("do action")
    }
}

尽管这里的 doAction() 办法并不是静态方法,然而咱们依然能够应用 Util.doAction() 的形式来调用,这就是单例类所带来的便利性。

companion object

不过,应用单例类的写法会将整个类中的所有办法全副变成相似于静态方法的调用形式,而如果咱们只是心愿让类中的某一个办法变成静态方法的调用形式该怎么办呢?这个时候就能够应用刚刚在最佳实际环节用到的 companion object 了,示例如下:

class Util {fun doAction() {println("do action")
    }

    companion object {fun doAction2() {println("do action2")
        }
    }
}

这里首先咱们将 Util 从单例类改成了一个一般类,而后在类中间接定义了一个 doAction1() 办法,又在 companion object 中定义了一个 doAction2() 办法。当初这两个办法就有了实质的区别,因为 doAction1() 办法是肯定要先创立 Util 类的实例能力调用的,而 doAction2() 办法能够间接应用 Util.doAction2() 的形式调用。

不过,doAction2() 办法其实也并不是静态方法,companion object 这个关键字实际上会在 Util 类的外部创立一个伴生类,而 doAction2() 办法就是定义在这个伴生类外面的实例办法。只是 Kotlin 会保障 Util 类始终只会存在一个伴生类对象,因而调用 Util.doAction2() 办法实际上就是调用了 Util 类中伴生对象的 doAction2() 办法。

由此能够看出,Kotlin 的确没有间接定义静态方法的关键字,然而提供了一些语法个性来反对相似于静态方法调用的写法,这些语法个性根本能够满足咱们平时的开发需要了。

然而如果你确确实实须要定义真正的静态方法,Kotlin 依然提供了两种实现形式:注解和顶层办法。上面咱们来一一学习一下。

注解

先来看注解,后面应用的单例类和 companion object 都只是在语法的模式上模拟了静态方法的调用形式,实际上它们都不是真正的静态方法。因而如果你在 Java 代码中以静态方法的模式去调用的话,你会发现这些办法并不存在。而如果咱们给单例类或 companion object 中的办法加上 @JvmStatic 注解,那么 Kotlin 编译器就会将这些办法编译成真正的静态方法,如下所示:

class Util {fun doAction1() {println("do action1")
    }

    companion object {
        @JvmStatic
        fun doAction2() {println("do action2")
        }
    }
}

留神,@JvmStatic 注解只能加在单例类或 companion object 中的办法上,如果你尝试加在一个一般办法上,会间接提醒语法错误。

因为 doAction2() 办法曾经成为了真正的静态方法,那么当初不论是在 Kotlin 中还是在 Java 中,都能够应用 Util.doAction2() 的写法来调用了。

顶层办法

再来看顶层办法,顶层办法指的是那些没有定义在任何类中的办法,比方咱们在上一节中编写的 main() 办法。Kotlin 编译器会将所有的顶层办法全副编译成静态方法,因而只有你定义了一个顶层办法,那么它就肯定是静态方法。

想要定义一个顶层办法,首先须要创立一个 Kotlin 文件。对着任意包名右击 → New → KotlinFile/Class,在弹出的对话框中输出文件名即可。留神创立类型要抉择 File。

点击“OK”实现创立,这样刚刚的包名门路下就会呈现一个 Helper.kt 文件。当初咱们在这个文件中定义的任何办法都会是顶层办法,比方这里我就定义一个 doSomething() 办法吧,如下所示:

fun doSomething() {println("do something")
}

方才曾经讲过了,Kotlin 编译器会将所有的顶层办法全副编译成静态方法,那么咱们要怎么调用这个 doSomething() 办法呢?

如果是在 Kotlin 代码中调用的话,那就很简略了,所有的顶层办法都能够在任何地位被间接调用,不必管包名门路,也不必创立实例,间接键入 doSomething() 即可,如下图所示:

但如果是在 Java 代码中调用,你会发现是找不到 doSomething() 这个办法的,因为 Java 中没有顶层办法这个概念,所有的办法必须定义在类中。那么这个 doSomething() 办法被藏在了哪里呢?咱们方才创立的 Kotlin 文件名叫作 Helper.kt,于是 Kotlin 编译器会主动创立一个叫作 HelperKt 的 Java 类,doSomething() 办法就是以静态方法的模式定义在 HelperKt 类外面的,因而在 Java 中应用 HelperKt.doSomething() 的写法来调用就能够了,如下图所示:

好了,对于静态方法的相干内容就学到这里。本大节中所学的常识,除了 @JvmStatic 注解不太罕用之外,其余像单例类、companion object、顶层办法都是 Kotlin 中非常罕用的技巧,心愿你能将它们牢牢把握。

退出移动版