内容:
- Kotiin对可空类型的显式的支持
- 可空类型的安全调用运算符
猫王运算符
安全类型转换
非空断言
let函数
延迟初始化的属性
可空类型的扩展函数
不用问号结尾,类型参数也能是可空的
平台类型
一可空类型必须显式支持
在java编写的代码的时候我们经常回碰到空指针异常的问题,kotlin为了减少和杜绝这种错的发生,提供了必须显示当前类型是否可以为null。默认全部不能为null
我们看下边一段java代码:
#java
public int getlength(String str){
return str.length();
}复制代码
这个函数在被调用的时候有可能会抛空指针异常,因为你控制不了外部传入的数据是否为null。
而对于Kotlin中去编写同样一段这样的代码,你必须指明当前传入的参数是否允许为null。
如果要求不能传入null,你必须这样写:
#kotlin
fun getlength(str: String): Int {
return str.length
}复制代码
如果要求可以传入null,你必须这样写:
fun getlength(str: String?): Int {
return str.length//先忽略这行
}复制代码
如果你有一个可空的值,你操作他们都会受到限制,例如:
1.可空类型不能直接调用他的方法:
上边传入字符串可null,调用方法str.length就会报错复制代码
2.不能把可空类型的值传给拥有非空类型参数的函数
#错误代码
val str:String? = "我可能为null"
var str2:String = str复制代码
怎么样能解除这些限制呢?
因为上边错误代码,在开发中是非常常见的写法。
解决:和null比较,在这次比较的作用域中编译器都是把它看成非null看待。
fun getlength(str: String?): Int {
return if (str != null) str.length else 0
}复制代码
这种解决方法比java的代码还要啰嗦,kotlin提供了一些工具来帮助我们用更简洁的方式来处理可空值。
二 可空类型安全调用运算符?.
他是把可空类型检查和调用合并在一起使用:
val str: String? = "我可能为null"
str?.length复制代码
这个调用的代码等同于
if (str!=null) str.length else null复制代码
注意:这次安全调用的结果有可能也是null,如
fun getlength(str: String?): Int? {
return str?.length
}复制代码
返回值有可能为null,所以返回值也是可null类型。
它不仅可以安全调用方法,还可以安全调用属性如:
class Book(val name :String , val author :List<String>?)复制代码
val book = Book("小三上位", null)
book.author?.size复制代码
且安全调用可以在一个表达式中连续使用。如下代码:
class Person(val name:String ,val company :Company?){
fun getCity():String{
val str = company?.address?.city
return if (str!=null) str else "UnKnow"
}
}复制代码
class Company(val name :String, val address :Address?)复制代码
class Address(val city :String)复制代码
可以看到上边的Person类里边连续使用了安全调用属性,且代码最后用if去判断是否是null,来处理是null的情况。
那么我们能把这里的非空判断去掉吗?
需要引入一个新的运算符 ?:
三 猫王运算符 ?:
修改上边person类变成这样
class Person(val name: String, val company: Company?) {
fun getCity(): String {
return company?.address?.city ?: ""
}
}复制代码
写法: 运算数1?: 运算数2
四安全类型转换 as?
我们在第一篇文章中知道使用is关键字去判断一个类型属于另外一个类型,如果是,他会自动转换。并且还知道可以使用as关键字去显示的转换一个类型到另外一个类型。
注意:假如我们没有判断一个类型属于不属于另外一个类型,而是直接as类型转换,这个时候如果是这个类型没有问题,如果不是这个类型,直接都会报类型转换异常的错误。
对于这个问题kotlin给出了安全类型转换
open class Father复制代码
class Son复制代码
val son = Son()
val iss = son as? Father复制代码
这个时候就不会报类型转换异常,而对应的返回的iss就是一个null类型。
我们常常回结合猫王运算符一起使用:
val iss = son as? Father?: false复制代码
这样再很多场景都可以用到类似这样的表达式
fun aaa(o: Any?): Boolean {
这里如果不是这个类型,直接返回false,如果是这个类型,下边就可以用这个类型的方法
val bbb = o as? Son ?: return false
return bbb.name=="张三"
}复制代码
五 非空断言
val str :String? = ""
val str2 = str!!
str2.length复制代码
这里对str做了非空断言,如果为null,就会直接抛空指针异常的错误。抛异常的是断言的那行代码。
六let函数
我们在实际开发中常常遇到这样一种情况,调用这个函数是允许传递null值的,但是我们要传递的确实一个可空参数,像这样:
fun sentEmall(email: String){
}复制代码
调用:
val str: String? = "xxxx@qq.com"
if (str != null)
sentEmall(str)复制代码
这里需要加上一个非空的判断,Kotlin给我们提供另外一种处理方式:使用let函数
str?.let { sentEmall(it) }复制代码
这里使用要传递的参数调用let函数,里边传递一个表达式,如果str不为null,就后调用sentEmall方法,且it就是这个str的非空,如果str为null,就不会调用sentEmall方法。
注意let方法可以嵌套调用,像这样:
fun sentEmall(address: String ,content:String) {
}复制代码
val str1: String? = "xxxx@qq.com"
val str2: String? = "xxxx@qq.com"
str1?.let { it->str2?.let { sentEmall(str1,str2) } }复制代码
七延迟初始化的属性
这不就扯淡了嘛!
但是kotlin为我们提供了延迟初始化来解决这个问题。类似这样:
lateinit var string :String复制代码
八可空类型的扩展函数
我们在java中一定没有用null值去调用过一个函数,而在kotlin中可以使用null去调用两个函数,而且不用安全调用,这两个函数分别是:isNullOrEmpty(),isNullOrBlank(),他们是null类型的扩展函数,isNullOrEmpty()是判断是否是null或者空字符串,isNullOrBlank是判断是否是null或者空格字符串。
但是我们上边提到一个let函数,他必须安全调用,否则会报错。因为他并不是检查调用者是否为null。
九不用问号结尾,类型参数也能是可空的。
fun <T> aaaa(t: T) {
t?.hashCode()
}复制代码
如果不想要泛型是可空的,我们需要指定类型,像这样:
fun <T:Any> aaaa(t: T) {
t.hashCode()
}复制代码
十 平台类型
java中的变量在kotlin中既可以当成可空类型,也可以当成非可空类型去处理,而且不会提示到底是不是null,这个需要你自己去判断是否为null。这就是所谓的转化成平台类型。平台类型在kotlin中不能声明,该类型只能来至java中。
小结
- Kotlin中需要显示的表现出可空类型,用?加到类型后边
- Kotlin中对于可空类型,需要安全调用,不管是方法还是属性,用?.去调用,如果是null,整个表达式就会返回null
- Kotlin中对猫王操作符,需要使用 左边?:右边,如果左边是null,直接返回右边。
- 安全转换 as?防止出现类型异常转换错误
- 非空断言,!! 简单除暴告诉编译器,他不是null
- let函数开发中非空和可空的麻烦问题,可嵌套使用
- 延迟初始化,可在构造方法外初始化,如果未初始化就使用,会报错
- 可空类型扩展的两个方法介绍
- 不使用?,类型也可能为null的特殊情况
- 平台类型既可以是可空又可以为非空