抓住今天,尽可能少的信赖明天。 喝汤能补 (* ^ ▽ ^ *)
前言
该文章作为学习交流,如有错误欢迎各位大佬指正 (* ^ ▽ ^ *)
- 自身技能
(1)已具备计算机的基本知识 - 本文简介
主要讲解:关于null的语法,空值判断的方式,变量延迟初始化的方式,以及kotlin是如何保证空指针安全的。
如果进行过Android项目开发者,经常会遇到空指针的问题,虽然解决方法不难,但是这个问题经常会导致程序崩溃,对应的到生活中口袋就瘦了。
可空类型系统
Kotlin默认所有的参数和变量都是不可为空的。当然也提供了一套可空的类型系统。
- 需要我们在编译时期就将所有潜在的空指针异常处理掉,否则无法编译通过。保证运行时,无空指针的问题。
- 语法: 在类名的后面加上 ? 。 如:String 不可为空的字符串,String? 可为空null的字符串
上代码
fun main() {
useFun(null) //直接报红
useFun1(null) //可以编译通过
}
fun useFun(an: Animal){
an.eat()
an.say()
}
fun useFun1(an: Animal?){
if(an!=null){
an.eat()
an.say()
}
}
判空辅助工具:?.符号、?:符号、!! 符号
Kotlin提供了一系列的辅助工具,帮助我们轻松处理各种判空情况。
- 语法 ?.符号 。表示对象不为空时正常调用相应的语法,对象为空则不做任何操作。
if(an!=null){
an.eat()
an.say()
}
// 可以简写为
an?.eat()
an?.say()
- 语法 ?:操作符。该操作符的左边表达式的结果不为空,就返回左边表达式的结果,否则就返回右边表达式的结果。
val c = if (a != null){
a
}else{
b
}
// 将上面代码直接使用?:进行简写
val c = a ?: b
项目中,可以简化怎样的代码
fun getTextLength(text : String?) :Int{
if (text != null){
return text.length
}
return 0
}
// 可以通过 ?. 与 ?: 进行简化
fun getTextLength0(text: String?) = text?.length ?: 0
Kotlin的空指针检查机制 ,不一定能判断出我们程序所有的非空情况。
如下代码中,逻辑上没有问题,但Kotlin却无法正常编译过,因为geStrLength()函数不知道外部已经进行了为空判断,所以认为str.length的str可能为空。
- !! 操作符,Kotlin提供的非空断言工具, 在需要的对象后面加上!! ,表示非常确信这里对象不为空,不需要进行空指针检查。
这种方式并不推荐,使用不当就会引发程序问题
val str : String? = "AAA"
fun main() {
if (str != null){
geStrLength()
}
}
fun geStrLength(){
println(str.length) // 无法编译通过
println(str!!.length)
}
let函数–标准函数
let函数,将原始调用对象作为参数传递到Lambda表达式中。
val obj=""
obj.let {
obj2 ->
//编写具体的业务
}
将obj对象传递到lambda表达式中,参数名为obj2,但obj与obj2 是同一个对象。
- let可以用来处理全局变量为空判断,而if则不行,因为无法保证if语句中的全局变量不被其他线程所修改。
使用let与?.更加简化为空判断
fun useFun1(an: Animal?){
an?.eat()
an?.say()
}
// 优化
fun useFun2(an: Animal?){
an?.let {
a ->
a.say()
a.eat()
}
}
// 上篇说的,只有一个参数,可以使用it
an?.let {
it.say()
it.eat()
}
// 无法编译通过
var animal :Animal? = null
fun useFun3(an: Animal?){
if (animal != null){
animal.say() //还是报错,animal可能被其他线程修改成null
animal.eat()
}
}
**其他标准函数的使用,见常见标准函数 **
变量延迟初始化 lateinit
在程序中,定义全局变量时,往往会后初始化值,这时就需要将变量初始化为null,而因Kotlin的空指针检查机制,需要对明确知道不可能为空的对象,进行判空处理。所以,提供了延迟初始化的方式对这种问题进行优化。
延迟初始化:延迟初始化的关键字lateinit ,其作用就是告诉编译器,会在晚些时候对这个变量进行初始化,因此就无需在声明该变量时,就将它赋值为null。
-
使用延迟初始化后,如果在该对象使用前,未对其进行初始化,程序就会崩溃,并抛出kotlin.UninitializedPropertyAccessException: lateinit property xxx has not been initialized 异常。
-
判断全局变量是否已经初始化,避免重复初始化的操作。语法是::obj.isInitialized ,如下面代码 ::file.isInitialized。
private lateinit var file: File // 延迟对File类进行初始化
fun main() {
if (!::file.isInitialized){ // 判断是否已经初始化
file.exists()
}
}
觉得有帮助的点下赞哟,毕竟三连步骤更多,嘻嘻,谢谢大家的支持(* ^ ▽ ^ *)