总结下,最近开发中使用 Kotlin 的一些小 tips。
1. 尽可能使用 val 声明 Kotlin 的变量。
val 声明的变量表示不可变的,必须初始化,其他地方不能修改该值,是线程安全的。
2. Elvis操作符 ?:
在无法判断变量是否有可能为空的情况下,不要写成显式的非 null 操作符 !!,尽量用 Elvis操作符 ?: ,特别是数值类型的时候,
如 var count = list?.length ?: 0
3. 尽量不要使用非空断言 !! (除非确保变量不为空)
可以使用 ? , ?: 或 lateinit 来避免编译器的可空提示
但使用 lateinit 时,务必确保使用的时候已经赋值(否则会报 kotlin.UninitializedPropertyAccessException: lateinit property bitmap has not been initialized
异常),并且确保赋的值一定不能为空(lateinit定义的值是非空的)
为了避免因为未初始化引起的异常问题,Kotlin 语言为每一个 lateini 属性实例提供了一个判断是否已经初始化的属性值 isInitialized (但要依赖于 Kotlin 的反射)
1 | private lateinit var user: User |
4. 安全转换 “as?”
注意类型转换关键字 as, 也有可能转换失败的情况(直接抛异常),要使用 as? ,转换失败时返回null, 对 null 做判断;
1 | var value = obj as? User ?: User() //表示如果 obj 强转为 User 失败时,new 一个 User 对象 |
5. open 关键字
Kotlin 中类和类的方法默认是 final 的,即不允许继承和重写。这主要是为了减少继承,避免脆弱基类的问题。想要实现继承或重写,需要加 open 关键字修饰
6. 注意声明或调用 Kotlin 的函数是,参数是否可为 null
定义 Kotlin 函数时,需要注意传入的参数是否有可能为 null;如果外部传参有可能会传 null 的话,要加一个可为 null 操作符 ? 的逻辑,否则如果直接传 null 会造成程序异常,特别是外部传参是 Java 代码传的情况,编译器是不会提示的不可为 null 的(是可以编译通过的,但 Kotlin 不能编译通过),例如:
1 | //kotlin |
7. Kotlin object 的特点
通过 object 实现的单例是一个饿汉式的单例,并且实现了线程安全;
object: 也可以用来创建匿名类的对象;
8. top-level property / function 顶层声明
把属性和函数的声明不写在 class 里面,这个在 Kotlin 里是允许的。这样写的属性和函数,不属于任何 class,而是直接属于 package,它和静态变量、静态函数一样是全局的,但用起来更方便:你在其它地方用的时候,就连类名都不用写;
如果在不同文件中声明命名相同的函数,使用的时候不会混淆,会自动导入不同包名
9. Kotlin 泛型
- 和 Java 的泛型一样,Kotlin 中泛型本身也是不可变的,需要用关键字
out
和in
才能设置型变
a. 使用关键字out
支持协变,等同于 Java 中的上界通配符? extends
;
b. 使用关键字in
支持逆变,等同于 Java 中的下界通配符? super
;
例如,参考 Kotlin 的泛型
1 | //out |
Kotin 的
*
星号投射是什么?
也就是类似 Java 的?
泛型通配符(相对于? extends Object
),kotlin 也就是out Any
,例如:var list: List<*>
where 关键字
Java 设置多个边界可以通过&
符号连接,而对应 Kotlin 的则是where
关键字,例如:1
2
3
4
5//Java: T 的类型必须同时是 Animal 和 Food 的子类型
class Monster<T extends Animal & Food>{
}
//Kotlin
class Monster<T> where T : Animal, T : Food
10. 多行输入符——三个双引号
三引号的形式用来输入多行文本,也就是说在三引号之间输入的内容将被原样保留,之中的单号和双引号不用转义,其中的不可见字符比如/n和/t都会被保留。比如 OpenGL
的 shader
代码用三引号的方式,代码更加直接直观。
1 | val str = """ |
更多 tips 可以参考:不要用Java的语法思维来写Kotlin
—EOF—