Kotlin——初級篇(六): 可空類型、空安全、非空斷言、類型轉換等特性總結

在咱們熟知的Java中,定義一個變量能夠默認不賦值,由於Java的系統會給咱們默認賦一個默認值,而且Java可定義一個賦值爲null的變量,這樣在使用這個變量的時候都會去顯示判斷該變量是否爲null。從代碼的簡潔性以及代碼的閱讀性來講,就差了Koltin一籌了,那麼Kotlin定義一個變量可爲null的變量怎麼定義呢?下面針對Kotlin的這些特性,做出一個詳細的講解。html

目錄

1、可空類型、空安全

在前面的變量、常量中咱們已經講解到了變量的定義。這裏不做詳述。若你有興趣,請參見Kotlin——初級篇(二):變量、常量、註釋git

1.一、定義一個可空類型的變量

定義一個可空類型的變量的格式爲:修飾符 變量名 : 類型? = 值github

這裏爲了演示,定義變量和定義可空變量的區別,會提到定義變量的代碼。數組

例:安全

// 定義一個不可爲空的變量,用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 的值爲 nullyii

分析:要定義一個可空類型的變量時,即在定義變量的類型後面加上?符號就好了。在使用的時候,記住要判斷該段該變量是否爲空,這個操做在Java中常常會用到...,若是定義一個不可爲空類型的變量時,則判斷將毫無心義,由於這個變量永遠不會爲空。ide

1.二、判斷可空類型的兩種使用方式

在上面咱們提到,可空類型須要判斷在使用,這裏介紹除了if ... else...以外的其餘方式函數

1.2.一、if...else...判斷post

例:ui

var str : String? = "123456"
str = null

if (str == null){
    println("變量str爲空")
}else{
    println("str.length => ${str.length}")
}
複製代碼

輸出結果爲:

變量str爲空
複製代碼

1.2.二、使用符號?.判斷

  • 該符號的用法爲:可空類型變量?.屬性/方法。若是可空類型變量爲null時,返回null
  • 這種用法大量用於鏈式操做的用法中,能有效避免空引用異常(NullPointException),由於只要鏈式其中的一個爲null,則整個表達式都爲null

例:

var str : String? = "123456"
str = null

println(str?.length)   // 當變量str爲null時,會返回空(null)
複製代碼

輸出結果爲:

null
複製代碼

1.2.三、鏈式調用

?.這種符號去判斷是否爲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.四、函數中使用可空類型的狀況下

當一個函數/方法有返回值時,若是方法中的代碼使用?.去返回一個值,那麼方法的返回值的類型後面也要加上?符號

例:

fun funNullMethod() : Int? {
    val str : String? = "123456"
    return str?.length
}
複製代碼

輸出結果爲:

6
複製代碼

1.2.五、let操做符

  • let操做符的做用:當時用符號?.驗證的時候忽略掉null
  • let的用法:變量?.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{}高階函數減小了好幾行代碼

Elvis操做符

Evils其實不是一個操做符,而是evil的複數,而evil的意思在這裏能夠理解爲屏蔽、安全的操做符,這樣的操做符有三種:

  1. ?: 這個操做符表示在判斷一個可空類型時,會返回一個咱們本身設定好的默認值.
  2. !! 這個操做符表示在判斷一個可空類型時,會顯示的拋出空引用異常(NullPointException).
  3. as? 這個操做符表示爲安全的類型轉換.

2.一、?:操做符

當咱們定義了一個可空類型的變量時,若是該變量不爲空,則使用,反之使用另一個不爲空的值

例:

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.二、!!操做符

!!操做符可謂是給愛好空引用異常(NullPointException)的開發者使用,由於在使用一個可空類型變量時,在該變量後面加上!!操做符,會顯示的拋出NullPointException異常

例:

val testStr : String? = null
println(testStr!!.length)
複製代碼

輸出結果爲:

能夠看出,在未作空判斷的狀況下直接使用操做符!!的狀況下,拋出了空異常

2.三、as?操做符

其實這裏是指as操做符,表示類型轉換,若是不能正常轉換的狀況下使用as?操做符。當使用as操做符的使用不能正常的轉換的狀況下會拋出類型轉換(ClassCastException)異常,而使用as?操做符則會返回null,可是不會拋出異常

2.3.一、使用as

例:

// 會拋出ClassCastException異常
val num1 : Int? = "Koltin" as Int
println("nun1 = $num1")
複製代碼

輸出結果爲:

2.3.二、使用as?

例:

val num2 : Int? = "Koltin" as? Int
println("nun2 = $num2)
複製代碼

輸出結果爲:

num2 = null
複製代碼

參考

Kotlin 空安全
Koltin官網文檔

總結

這一章在實際的項目開發當中用到的地方是不少的,若是用好了各類空安全的操做符,估計你的項目中就不會拋出以及異常了,在這裏我作了一個總結,但願會對各位有所幫助:

  • 項目中會拋出空引用(NullPointerException)異常的狀況
    1. 在可空類型變量的使用時,用了!!操做符
    2. 顯式拋出空引用異常 throw NullPointerException()
    3. 外部 Java 代碼致使的
    4. 對於初始化,有一些數據不一致(如一個未初始化的 this 用於構造函數的某個地方)
  • 項目中會拋出類型轉換(ClassCastException)異常的狀況
    1. 在類型轉換中使用了as操做符
    2. 使用了toXXX()方法不能轉換的狀況下
    3. 外部 Java 代碼致使的
  • 儘可能避免使用的操做符
    1. 儘量的不要使用!!操做符,多使用?:?.操做符,以及let{}函數
    2. 儘量的使用as?操做符去替換掉as,在不肯定是否能夠安全轉換的狀況下不使用toXXX()方法

源代碼

若是各位大佬看了以後感受還闊以,就請各位大佬隨便star一下,您的關注是我最大的動力。
個人我的博客Jetictors
個人githubJetictors


歡迎各位大佬進羣共同研究、探索

QQ羣號:497071402

相關文章
相關標籤/搜索