文章目录
1 lateinit
lateinit 推迟属性初始化
// 在 Kotlin 中,必须在声明对象时初始化对象
val languageName: String? = null
// 使用lateinit后便可不必在声明时初始化了
lateinit val languageName: String
2 OnClickListener回调函数简化(SAM转换)
loginButton.setOnClickListener {
// 当用户点击 loginButton 时,系统会执行下面的代码,
// 相当于在onClick()方法中执行的
}
3 伴生对象companion
相当于static
class LoginFragment : Fragment() {
...
companion object {
private const val TAG = "LoginFragment"
}
}
4 属性委托 by
private val viewModel: LoginViewModel by viewModels()
- 只能用于常量val
- 相当于单例模式(如果为空,则初始化,否则直接得到值)。
- 只有在第一次调用的时才执行 by 后的表达式,对变量赋值,
- 后面再调用就直接获取到变量的值了,不会再次执行by 后的表达式了。
举例子:
val tes : String by lazy {
println("compute")
"hello"
}
fun main(args: Array<String>) {
println(tes)
println(tes)
}
输出:
compute
hello
hello
5 !! 与?与?:
!! 表示确信变量一定不为空,如果为空的话抛出异常,这就跟java一样了
val account = Account("name", "type")
val accountName = account.name!!.trim()
?表示变量可为空,为空了也不抛出异常,将空传递下去,在我这是管不了了,爱咋咋滴
val account = Account("name", "type")
// account.name为空的话,调用trim()不抛异常,而是返回null
val accountName = account.name?.trim()
?:为?做个兜底保障,都不管了我得管。它后面会跟一个默认值,表示为空的话,就取它后面的默认值
val account = Account("name", "type")
val accountName = account.name?.trim() ?: "Default name"
6 Map与FlatMap
map:遍历每一个元素
flatMap:遍历每一个元素,并铺平元素
var list =listOf(listOf(10,20),listOf(30,40),listOf(50,60))
var mapList = list.map{element->element.toString()}
var flatMapList = list.flatMap{element->element.asIterable()}
flatMap中的函数一定要返回一个Iterable,不然报错
结果:
[[10, 20], [30, 40], [50, 60]]
[10, 20, 30, 40, 50, 60]
7 函数类型
函数类型必须要具有函数的 参数 和 返回值类型
所有函数类型都有一个圆括号括起来的参数类型列表,以及一个返回类型:(A, B) -> C ,参数列表与返回值类型之间通过 -> 符号连接。(A, B) -> C表示接收类型分别为 A 与 B 两个参数并返回一个 C 类型值的函数类型。
eg:
val f: (Int) -> String
() -> String
(Int) -> Unit // Unit表示无返回值
赋值eg:
val block: (Int, Int) -> Int = ::sum
fun sum(firstNumber: Int, secondNumber: Int): Int {
return firstNumber + secondNumber
}
函数类型的变量需要接收函数类型的对象,那怎么才能得到函数类型的对象呢?Kotlin为我们提供了双冒号(::)来创建函数类型对象的引用。
调用:
val block: (Int, Int) -> Int = ::sum
// 以下调用都是有返回值的,因为(Int, Int) -> Int这个函数类型是有返回值的
block(1, 2)
// 等价于
block.invoke(1, 2)
// 等价于
(::sum)(1, 2)
// 等价于
(::sum).invoke(1, 2)
函数类型的对象后面可以加括号调用,等价于调用原函数。其实这是Kotlin为我们提供的一个语法糖,它本质上还是会去调用该对象的invoke函数
8 高阶函数
一个函数的参数列表中存在函数类型的参数或是函数的返回值类型为函数类型,那么这个函数就叫做高阶函数
9 匿名函数
没有名字的函数,无法直接调用。可以赋值给一个变量,或者当作实参直接传递给一个函数类型的形参。
匿名函数能够赋值给变量:
val filterWeightFunPredicate =
fun(appleBean: AppleBean): Boolean = appleBean.weight
一旦我们将一个匿名函数赋值给一个变量,那个这个变量其实就是一个函数类型的对象,函数类型为:(AppleBean) -> Boolean
我们也可以直接将匿名函数传入另一个函数
filterApple(appleList, fun(appleBean: AppleBean): Boolean
= appleBean.weight > 6)
实际上你传递的是一个对象,一个函数类型的对象。因为匿名函数它本来就不是函数,而是一个函数类型的对象。
10 Lambda表达式
Lambda表达式的本质是匿名函数,而匿名函数的本质是函数类型的对象。因此,Lambda表达式、匿名函数、双冒号+函数名这三个东西,都是函数类型的对象,他们都能够赋值给变量以及当作函数的参数传递!
Lambda表达式被大括号包围着
Lambda表达式的参数在->的左边,如果没有参数,则只保留函数体
Lambda表达式的函数体在->的后面
Lambda表达式的返回类型值总为函数体最后一行代码的返回值类型
彻底搞懂Kotlin的高阶函数、匿名函数、Lambda表达式: https://www.jianshu.com/p/8eb0623f08c6
11 Kotlin中,理解T.()->Unit 、 ()->Unit与(T) -> Unit
-
()->Unit与(T) -> Unit是相同的,只是一个带参,一个不带参
-
(T) -> Unit通过形参T可将对象作为实参传给函数,所以函数体里能通过it或者指定名称的方式来访问该对象
-
T.()->Unit 等同于为T定义了一个无参数的扩展函数,所以在函数体内可以直接通过this或省略来访问T代表的对象
举例:
官方 kotlin 扩展方法 apply、also
fun T.apply(block: T.() -> Unit): T { block(); return this }
fun T.also(block: (T) -> Unit): T { block(this); return this }
使用:
//定义了一个Person类
class Person(val name:String){
var age:Int = 0
var sex:Int = 0
}
fun test() {
val person= Person("张三")
person.also {
//没有指定参数名字,必须用it代指参数
it.age = 20 //it不能省略
it.sex = 0 //it不能省略
}
//或者
person.also {personValue->
//使用指定的参数名,同样personValue不能省略
personValue.age = 20
personValue.sex = 0
}
person.apply {
//直接访问Person的属性
this.age = 20 //this可以省略
this.sex = 1 //this可以省略
}
}
https://www.jianshu.com/p/f3ca07b582e5