
在我們熟知的Java中,定義一個變量可以默認不賦值,因為Java的系統會給我們默認賦一個默認值,並且Java可定義一個賦值為null的變量,這樣在使用這個變量的時候都會去顯示判斷該變量是否為null。從代碼的簡潔性以及代碼的閱讀性來說,就差了Koltin一籌了,那么Kotlin定義一個變量可為null的變量怎么定義呢?下面針對Kotlin的這些特性,作出一個詳細的講解。
目錄

一、可空類型、空安全
在前面的變量、常量中我們已經講解到了變量的定義。這里不作詳述。若你有興趣,請參見Kotlin——初級篇(二):變量、常量、注釋
1.1、定義一個可空類型的變量
定義一個可空類型的變量的格式為:
修飾符 變量名 : 類型? = 值
這里為了演示,定義變量和定義可空變量的區別,會提到定義變量的代碼。
例:
// 定義一個不可為空的變量,用var修飾的變量可以被重新賦值,用val修飾的變量則不能,但是不能賦值為null
var a : Int = 12
val b : Int = 13
a = 20
// a = null 不能復制為null
// b = 20 不能被重新賦值
if(a == null){
// 這樣的判斷毫無意義,因為變量a永遠不可能null
}
/*
定義可空類型的變量,即變量可以被賦值為null
定義格式為:修飾符 變量名 : 類型? = 值
*/
var nullA : Int? = 12
val nullB : Int? = 13
nullA = null
if(nullA == null){
println("nullA = $nullA")
}
可以看出:變量 nullA 的值為 null
分析:要定義一個可空類型的變量時,即在定義變量的類型后面加上?符號就行了。在使用的時候,記住要判斷該段該變量是否為空,這個操作在Java中經常會用到...,如果定義一個不可為空類型的變量時,則判斷將毫無意義,因為這個變量永遠不會為空。
1.2、判斷可空類型的兩種使用方式
在上面我們提到,可空類型需要判斷在使用,這里介紹除了
if ... else...之外的其他方式
1.2.1、if...else...判斷
例:
var str : String? = "123456"
str = null
if (str == null){
println("變量str為空")
}else{
println("str.length => ${str.length}")
}
輸出結果為:
變量str為空
1.2.2、使用符號?.判斷
- 該符號的用法為:
可空類型變量?.屬性/方法。如果可空類型變量為null時,返回null- 這種用法大量用於鏈式操作的用法中,能有效避免
空引用異常(NullPointException),因為只要鏈式其中的一個為null,則整個表達式都為null
例:
var str : String? = "123456"
str = null
println(str?.length) // 當變量str為null時,會返回空(null)
輸出結果為:
null
1.2.3、鏈式調用
?.這種符號去判斷是否為null,在Kotlin中使用的地方是很多,特別是對於鏈式調用來說體驗性更好。
例:這里簡單寫一個建造者模式,來模擬?.在鏈式調用中的用法
class Test{
class Builder{
private var name : String? = "Tom"
private var age : Int? = 0
private var sex : String? = "男"
fun setName(name : String) : Builder?{
this.name = name
return this
}
fun setAge(age : Int) : Builder?{
this.age = age
return this
}
fun setSex(sex: String?) : Builder?{
this.sex = sex
return this
}
override fun toString(): String {
return "Builder(name=$name, age=$age, sex=$sex)"
}
}
}
fun main(args: Array<String>) {
val builder : Test.Builder? = Test.Builder().setName("Lily")?.setSex("nv")?.setAge(10)
println(builder.toString())
}
輸出結果為:
Builder(name=Lily, age=10, sex=女)
如果你上面的代碼看不懂可以看下的代碼,你可以看下面的例子:頂一個可空類型的字符串的長度加5再減去10
val testStr : String? = null
val result = testStr?.length?.plus(5)?.minus(10)
println(result)
可以看出輸出結果為: null
1.2.4、函數中使用可空類型的情況下
當一個函數/方法有返回值時,如果方法中的代碼使用
?.去返回一個值,那么方法的返回值的類型后面也要加上?符號
例:
fun funNullMethod() : Int? {
val str : String? = "123456"
return str?.length
}
輸出結果為:
6
1.2.5、let操作符
let操作符的作用:當時用符號?.驗證的時候忽略掉nulllet的用法:變量?.let{ ... }
例:排除掉數組中的空元素
val arrTest : Array<Int?> = arrayOf(1,2,null,3,null,5,6,null)
// 傳統寫法
for (index in arrTest) {
if (index == null){
continue
}
println("index => $index")
}
// let寫法
for (index in arrTest) {
index?.let { println("index => $it") }
}
輸出結果為:
index => 1
index => 2
index => 3
index => 5
index => 6
注意:上面的兩種寫法的效果是相同的,可以看出使用let{}高階函數減少了好幾行代碼
Evils操作符
Evils其實不是一個操作符,而是evil的復數,而evil的意思在這里可以理解為屏蔽、安全的操作符,這樣的操作符有三種:
?:這個操作符表示在判斷一個可空類型時,會返回一個我們自己設定好的默認值.!!這個操作符表示在判斷一個可空類型時,會顯示的拋出空引用異常(NullPointException).as?這個操作符表示為安全的類型轉換.
2.1、?:操作符
當我們定義了一個可空類型的變量時,如果該變量不為空,則使用,反之使用另外一個不為空的值
例:
val testStr : String? = null
var length = 0
// 例: 當testStr不為空時,輸出其長度,反之輸出-1
// 傳統寫法
length = if (testStr != null) testStr.length else -1
// ?: 寫法
length = testStr?.length ?: -1
println(length)
輸出結果為:
-1
分析:此操作符一般和?.操作符連用。當且僅當?:左邊的表達式為null時,才會執行?:右邊的表達式。
2.2、!!操作符
!!操作符可謂是給愛好空引用異常(NullPointException)的開發者使用,因為在使用一個可空類型變量時,在該變量后面加上!!操作符,會顯示的拋出NullPointException異常
例:
val testStr : String? = null
println(testStr!!.length)
輸出結果為:

可以看出,在未做空判斷的情況下直接使用操作符!!的情況下,拋出了空異常
2.3、as?操作符
其實這里是指
as操作符,表示類型轉換,如果不能正常轉換的情況下使用as?操作符。當使用as操作符的使用不能正常的轉換的情況下會拋出類型轉換(ClassCastException)異常,而使用as?操作符則會返回null,但是不會拋出異常
2.3.1、使用as
例:
// 會拋出ClassCastException異常
val num1 : Int? = "Koltin" as Int
println("nun1 = $num1")
輸出結果為:

2.3.2、使用as?
例:
val num2 : Int? = "Koltin" as? Int
println("nun2 = $num2)
輸出結果為:
num2 = null
總結
這一章在實際的項目開發當中用到的地方是很多的,如果用好了各種空安全的操作符,估計你的項目中就不會拋出以及異常了,在這里我做了一個總結,希望會對各位有所幫助:
- 項目中會拋出
空引用(NullPointerException)異常的情況- 在可空類型變量的使用時,用了
!!操作符 - 顯式拋出空引用異常
throw NullPointerException() - 外部 Java 代碼導致的
- 對於初始化,有一些數據不一致(如一個未初始化的 this 用於構造函數的某個地方)
- 在可空類型變量的使用時,用了
- 項目中會拋出
類型轉換(ClassCastException)異常的情況- 在類型轉換中使用了
as操作符 - 使用了
toXXX()方法不能轉換的情況下 - 外部 Java 代碼導致的
- 在類型轉換中使用了
- 盡量避免使用的操作符
- 盡可能的不要使用
!!操作符,多使用?:、?.操作符,以及let{}函數 - 盡可能的使用
as?操作符去替換掉as,在不確定是否可以安全轉換的情況下不使用toXXX()方法
- 盡可能的不要使用
如果各位大佬看了之后感覺還闊以,就請各位大佬隨便star一下,您的關注是我最大的動力。
我的個人博客:Jetictors
我的github:Jetictors
我的掘金:Jetictors
