在写这篇文章之前,Kotlin的基础和进阶课程都已经学习完了。这里简单做一个总结:
-
[Kotlin基础学习(一)]主要知识点:Kotlin中的变量与函数,逻辑控制,类与对象
-
[Kotlin基础学习(二)]主要知识点:集合的创建与遍历,Lambda编程
-
[Kotlin基础学习(三)]主要知识点:空指针检查,Kotlin中的简单特性
-
[Kotlin进阶学习(四)] 主要知识点:标准函数,静态方法,变态延迟初始化与密封类
-
[Kotlin进阶学习(五)]主要知识点:扩展函数,运算符重载,高阶函数,内联函数
-
[Kotlin进阶学习(六)]主要知识点:高阶函数的应用,泛型基础,infix函数
-
[Kotlin进阶学习(七)]主要知识点:泛型高级,委托
-
[Kotlin进阶学习(八)]主要知识点:协程的内容
空指针检查
通常情况,我们在安卓开发中总是需要对某个控件或变量进行判空,以确保他不会造成空指针异常。但一旦项目的代码量上去了,总会有出错的时候。Kotlin通过在编译时对判空进行检查,虽然这么搞有时候会让代码很难写,但Kotlin还提供了很多的辅助工具方便处理。
可空类型系统
我们先来看一段代码:
fundoStudy(s:String){
s.toUpperCase()
s.toLowerCase()
}
这段看上去似乎有着空指针的风险,但实际上是没有的,因为Koltin默认所有的参数和变量都不可为空。所以这里传入的String参数一定不会为空,调用其中的方法自然没有任何问题。如果你尝试给他传入一个null参数,编译器会报错:
Null can not be a value of a non-null type String
也就是说,Kotlin将空指针异常的检查提前到了编译时期,如果有空指针异常的风险直接不通过编译,更不要谈运行时报错了。这样就从根本上杜绝了空指针异常。
但你看到这里可能会觉得诧异,那我如果真的需要传入一个null值怎么办?Kotlin为我们提供了另外一套可为空的类型系统,即在变量类型后面加上问号即可,如:
fundoStudy(s:String?){
s.toUpperCase()
s.toLowerCase()
}
但这时候你会发现出现了红点:
很正常,因为此时我们的s是有可能为空的,必须排除他为空的可能,如下:
fundoStudy(s:String?){
if(s != null){
s.toUpperCase()
s.toLowerCase()
}
}
这样就完事了,但我们发现,好像和之前用Java没什么区别啊?我不是还得写一堆的判空语句吗。别急,下面来学习Kotlin提供的辅助工具来更轻松的进行判空。
判空辅助工具
- 首先来学习最常用的?.操作符,这个符号的意思很好理解——当对象不为空时调用相应的方法,当对象为空的时候就什么都不做,比如我们上面的判空语句:
fundoStudy(s:String?){
s?.toUpperCase()
s?.toLowerCase()
}
还是很简单的吧?有了他我们就可以极大的简化我们的代码了。
- 学习了?.后,再来学习一个也很常用的?:操作符,这个操作符左右都接收一个表达式,如果左边表达式的结果不为空则返回左边表达式的结果,否则就返回右边的结果,比如:
val c = if(a != null){
a
}else{
b
}
这段代码的逻辑用?:操作符就可以简化成:
val c = a ?: b
当然,我们也可以将?.和?:一起用起来:
fungetTextLength(text:String?) = text?.length ?: 0
这里使用了函数里单行代码的语法糖,并且结合了?.和?:。具体来看,当text为空时,就会返回0值,当text不为空时,就会返回它的长度length。
- 当然,有时候Kotlin的编译器并不是那么智能。有的时候我们已经从逻辑上将空指针异常处理了,但Kotlin的编译器不知道,这时候还是会编译失败。比如以下这段代码:
var content:String? = "hello"funmain(){
if(content != null){
printUpperCase()
}
}
funprintUpperCase(){
val upperCase = content.toUpperCase()
println(upperCase)
}
这里我们定义了一个可为空的全局变量content,然后在主函数里对其进行了判空处理,当content不为空时才会调用下面的方法输出它的大写值。从逻辑上讲似乎没什么问题,但这段代码无法通过编译。因为printUpperCase()这个方法并不知道外部对content已经进行了判空处理,在调用toUpperCase()方法时还是会认为存在空指针异常。
这种情况下,我们可以使用非空断言工具,写法是在对象的后面加上!!,如:
funprintUpperCase(){
val upperCase = content!!.toUpperCase()
println(upperCase)
}
断言,意思就是告诉编译器,我非常确信这里不会为空,你就不用管了。但这种工具如果自己不够确信的情况下,还是不要随意使用的。万一一个不好,就出了空指针异常。
- 最后,学习一个函数let,通过这个函数的特性可以帮助我们简化空指针检查时的代码。let是一个函数,里面要传入一个Lambda表达式,且会把原始调用对象作为参数传递到Lambda表达式里。那么怎么用他来简化我们的代码呢?如下:
fundoStudy(s:String?){
s?.toUpperCase()
s?.toLowerCase()
}
这是我们之前的代码,我们使用let函数:
fundoStudy(s:String?){
s?.let{s ->
s.toUpperCase()
s.toLowerCase()
}
}
再根据之前学习的Lambda表达式的特性,代码进一步简化:
fundoStudy(s:String?){
s?.let{
it.toUpperCase()
it.toLowerCase()
}
}
要解释的话其实很简单,当对象不为空的时调用let函数,此时的s对象一定不为空,自然可以随便调用里面的方法了。
let函数一般用在判断全局变量的时候。在对全局变量判空时,使用if并不能通过编译,因为全局变量的值随时可能被其他线程修改啊,即使做了判空处理也不能确保他没有空指针风险。
Kotlin中的小魔术
到这里,我们已经学习了很多Kotlin的基础知识了。最后,我把书上提到的Kotlin中的小魔术也记录一下,学会了这些也会提升我们的编码速度。
字符串内嵌表达式
一般,我们在Java中连接字符串都会使用+号,但这种方式太繁琐了,一不小心我们就会写错。但Kotlin支持使用字符串内嵌表达式来简化我们的操作。先来看语法规则:
"hello ${obj.name} nice to meet you"
可以看到,Kotlin允许我们在字符串中嵌入${}这种语法结构的表达式,并会自动替换这部分内容。如果学过web的话,会发现el表达式也是这样的写法。另外,当表达式中仅有一个变量时,还可以省略大括号:
"hello $name nice to meet you"
接下来我们直接在代码中使用呗,如下:
val brand = "Samsung"val price = 1299.9
println("Cellphone(brand = $brand, price = $price)")
可以看到,无论是易读性还是易写性都上了一层楼,可以说十分方便了。
函数的参数默认值
如果我们学过C++的话,就会知道C++里是允许在函数上直接给变量一个默认值的。我们的Kotlin也是支持这种写法的。如:
funprintParams(num:Int,str:String = "hello"){
println("num is $num, str is $str")
}
这里我们就给str指定了默认值hello,当我们调用这个方法时:
printParams(123)
不传入str的值,输出的结果也会如我们所愿的。
这时候我们换换,给num一个默认值:
funprintParams(num:Int = 100,str:String){
println("num is $num, str is $str")
}
这时候我们怎么调用这个方法呢?像刚才那样的使用肯定是不行的,编译器会认为我们想把一个字符串赋值给第一个num参数,直接类型不匹配。这时候我们就可以使用键值对的写法了,如下:
printParams(str = "world")
这时候就无所谓先后顺序了,毕竟是按键值匹配的。
这里我们就提到最开始学习的次构造函数,我们说函数的参数默认值这个功能可以很大程度上替代次构造函数。为什么这么说呢?次构造函数的作用一般是什么呢?就是为类提供更多的赋值方式,方便调用。而我们直接在主构造函数上设置函数默认值能达到一样的效果,这时我们就可以使用任意传参组合了。
总结
仔细想想这一路的学习,会发现Kotlin借鉴了很多其他语言的优势,优化了Java的一些痛点。总的来说虽然Lambda表达式的使用和理解还是有些难度,但我想在日后更多的使用中会更加巩固这方面的知识吧。
关注公众号:Android老皮
解锁 《Android十大板块文档》 ,让学习更贴近未来实战。已形成PDF版
内容如下:
1.Android车载应用开发系统学习指南(附项目实战)
2.Android Framework学习指南,助力成为系统级开发高手
3.2023最新Android中高级面试题汇总+解析,告别零offer
4.企业级Android音视频开发学习路线+项目实战(附源码)
5.Android Jetpack从入门到精通,构建高质量UI界面
6.Flutter技术解析与实战,跨平台首要之选
7.Kotlin从入门到实战,全方面提升架构基础
8.高级Android插件化与组件化(含实战教程和源码)
9.Android 性能优化实战+360°全方面性能调优
10.Android零基础入门到精通,高手进阶之路
敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔