这是我参与「第四届青训营 」笔记创作活动的第11天
标准函数
Kotlin的标准函数指的是Standard.kt文件中定义的函数,任何Kotlin代码都可以自由地调用所 有的标准函数。
with
with函数接收两个参数:第一个参数可以是一个任意类型的对 象,第二个参数是一个Lambda表达式。with函数会在Lambda表达式中提供第一个参数对象的上下文,并使用Lambda表达式中的最后一行代码作为返回值返回。
val result = with(obj) {
// 这里是obj的上下文
"value" // with函数的返回值
}
在上下文环境中可以直接调用对象中的方法,而无需对象名
示例用法:整合集合中的字符串
val list2 = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result2 = with(StringBuilder()) {
append("Start eating fruits.\n")
for (fruit in list2) {
append(fruit).append("\n")
}
append("Ate all fruits.")
toString() // 返回最后结果
}
println(result2)
run
run函数的用法和使用场景其实和 with函数是非常类似的,只是稍微做了一些语法改动而已。首先run函数通常不会直接调用, 而是要在某个对象的基础上调用;其次run函数只接收一个Lambda参数,并且会在Lambda表 达式中提供调用对象的上下文。其他方面和with函数是一样的,包括也会使用Lambda表达式 中的最后一行代码作为返回值返回。
val result3 = obj.run {
// 这里是obj的上下文
"value" // run函数的返回值
}
使用示例:整合集合中的字符串
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result4 = StringBuilder().run {
append("Start eating fruits.\n")
for (fruit in list) {
append(fruit).append("\n")
}
append("Ate all fruits.")
toString()
}
println(result4)
apply
apply函数和run函数也是极其类似的,都要在某 个对象上调用,并且只接收一个Lambda参数,也会在Lambda表达式中提供调用对象的上下 文,但是apply函数无法指定返回值,而是会自动返回调用对象本身。
val result5 = obj.apply {
// 这里是obj的上下文
} // result5 就是一个 obj
使用示例
val list3 = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result6 = StringBuilder().apply {
append("Start eating fruits.\n")
for (fruit in list3) {
append(fruit).append("\n")
}
append("Ate all fruits.")
}
println(result6.toString())
安卓中的应用示例
启动Activity,这时传一个参数就要调用一次 putExtra() 函数
val intent = Intent(context, SecondActivity::class.java)
intent.putExtra("param1", "data1")
intent.putExtra("param2", "data2")
context.startActivity(intent)
使用 apply 简化
val intent = Intent(context, SecondActivity::class.java).apply {
putExtra("param1", "data1")
putExtra("param2", "data2")
}
context.startActivity(intent)
静态方法
Kotlin语法糖实现静态特性
传统Java 中的静态方法推荐使用单例类来实现
object Util {
fun doAction() {
println("do action")
}
}
调用
Util.doAction()
但是使用单例类将会把该类所有的方法都变成类似静态方法的特性,如果只想将一部分方法变为静态方法,可以用 companion object
class Util {
fun doAction1() {
println("do action1")
}
companion object {
fun doAction2() {
println("do action2")
}
}
}
doAction2()方法其实也并不是静态方法,companion object这个关键字实际上会在Util类的内部创建一个伴生类,而doAction2()方法就是定义在这个伴生类里面的实例方法。只是Kotlin会保证Util类始终只会存在一个伴生类对象,因此调用Util.doAction2()方 法实际上就是调用了Util类中伴生对象的doAction2()方法。
由此可以看出,Kotlin确实没有直接定义静态方法的关键字,但是提供了一些语法特性来支持类 似于静态方法调用的写法。
如果实在需要真正的静态方法,可以使用注解和顶层方法
注解实现单例
@JvmStatic注解 只能注解在单例类或者 companion object 的方法上,不能注解在普通方法上
class Util {
fun doAction1() {
println("do action1")
}
companion object {
@JvmStatic
fun doAction2() {
println("do action2")
}
}
}
顶层方法
顶层方法指的是那些没有定义在任何类中的方法, 比如 main() 方法。
Kotlin编译器会将所有的顶层方法全部编译成静态方法。
首先需要创建一个Kotlin文件。对着任意包名右击 → New → Kotlin File/Class,在弹出的对话框中输入文件名即可。注意创建类型要选择File
fun topMethod() {
println("topMethod !")
}
调用
fun main(args: Array<String>) {
topMethod() // 直接调用
}
比较常用的是 单例类,companion object 和顶层方法,@JvmStatic注解用的比较少。
延迟初始化
Kotlin 为了保证程序安全设计了许多的特性,比如变量默认不可为空,默认为常量等等,这些设计有时会给编码时带来麻烦。
例子
class MainActivity : AppCompatActivity(), View.OnClickListener {
private var adapter: MsgAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
adapter = MsgAdapter(msgList)
}
override fun onClick(v: View?) {
adapter?.notifyItemInserted(msgList.size - 1)
}
}
这里我们将adapter设置为了全局变量,但是它的初始化工作是在onCreate()方法中进行 的,因此不得不先将adapter赋值为null,同时把它的类型声明成MsgAdapter?。
虽然我们会在onCreate()方法中对adapter进行初始化,同时能确保onClick()方法必然在 onCreate()方法之后才会调用,但是我们在onClick()方法中调用adapter的任何方法时仍 然要进行判空处理才行,否则编译肯定无法通过。
要解决这个问题,可以使用 lateinit 关键字对全局变量进行延迟初始化。
class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var adapter: MsgAdapter
override fun onCreate(savedInstanceState: Bundle?) {
adapter = MsgAdapter(msgList)
}
override fun onClick(v: View?) {
adapter.notifyItemInserted(msgList.size - 1)
}
}
如果在初始化前使用了该全局变量,会抛出 UninitializedPropertyAccessException 异常
可以使用 ::adapter.isInitialized 来判断是否初始化
override fun onCreate(savedInstanceState: Bundle?) {
if (!::adapter.isInitialized) { // 发现全局变量还没初始化则立刻初始化
adapter = MsgAdapter(msgList)
}
}