iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
1
自我挑戰組

Android 菜鳥村-開發基礎 30篇系列 第 16

[Day 14 ] Kotlin 空(null)安全檢查

  • 分享至 

  • xImage
  •  

本篇文章大概會討論到下列幾個主題

  • 可空類型 及 null

  • 在條件中檢測 null

  • 安全的調用

  • Elvis 操作符

  • !! 操作符

可空類型 及 null

在 Kotlin 中, 常規变量不能容纳 null:

 fun main() {
    var a: String = "abc" // 默認情况下,常規初始化意味着非空
    a = null // 編譯錯誤
}

如果我們希望一個變數可以容許 空值(null)的存在, 可以像下面宣告, 在類型後面 加一個問號

fun main() {
   var a: String? = "abc"  // 可以設置为空
   a = null  // ok
   println(a)
   
   // result:
   // null
}

特定情況下訪問 null 的變數會導致 NullPointerException。

下面藉由了 !! 操作符 保證不為空 , 騙過了編譯器 , 但其實本質上還是 null
所以在運行時仍引發了 NullPointerException , 下面會介紹到 !! 操作符
是怎麼一回事

fun main() {
   var a: String? = null  // 可以設置为空  
   val l = a!!.toDouble()
   println(l)
   
   // error:
   // Exception in thread "main" java.lang.NullPointerException
}

這時我們會需要做空安全的檢查

在條件中檢測 null

先檢測 值 是否為 null,並分別處理兩種可能,這樣能有效防止 NullPointerException

fun main() {
  var a: String? = null  // 可以設置为空  
  // ok
  val l = if( a != null) a.toDouble() else -1
 
 println(l)
  
  // result
  // -1
}

Safe calls

寫法如下

如果 a 非空,就返回 a.toDouble(),否則返回 null,这个表達式的類型是 Double?。

fun main() {
 var a: String? = null  // 可以設置为空  
 // ok
 val l = a?.toDouble()

println(l)
 
 // result
 // null
}

但賦值給下一個變數時仍需做處理,否則依然會發生NullPointerException

 
 fun main() {
    var a: String? = null  // 可以設置为空  
    // ok
    val l = a?.toDouble()
    
    val b = l!!.compareTo(9.0)
   
   println(b)
    
    // error:
    // Exception in thread "main" java.lang.NullPointerException
}

Elvis 操作符

上面提到用 if 先檢測 值 是否為 null,並分別處理兩種可能


val l = if( a != null) a.toDouble() else -1

其實我們可以簡化成下面這樣

上面提到的 Safe Calls , 原本是非空的話,就返回 a.toDouble(),否則返回 null


val l = a?.toDouble()

現在我們加上 Elvis 操作符 , 是非空的話,就執行右邊內容 a.toDouble(), 如果 為null 則執行左邊內容 返回-1


val l = a?.toDouble()?: -1

!! 操作符

下面a 要調用 toDouble(),可是 a 雖然非空值("123")但他的型態 為 String?,在編譯階段就會報錯,提示必須傳入非空型態,這時候我們就可以調用 !! 保證他不為空 , 讓他可以過編譯器這一關 。

fun main() {
    var a: String? = "123"  // 可以設置为空  

    val l:Double= a.toDouble()// 未加!! 操作符
    
    println(l)
  
    // error:
    // Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable         
    //receiver of type String?
}

改成

fun main() {
    var a: String? = "123"  // 可以設置为空  

    val l:Double= a!!.toDouble() // 加上!! 操作符
    
    println(l)

}

他直接跳過這個 Kotlin 空安全檢查機制 保證不為空,如果是非空的值(像上面)不會報錯 ,但如果 a 是空值, 在編譯完後 仍然會 出現 NullPointerException

fun main() {
  var a: String? = null  // 可以設置为空  
  // ok
  val l:Double = a!!.toDouble()
  println(l)
  
  // error:
  // Exception in thread "main" java.lang.NullPointerException
}

上一篇
[Day 13 ] Object declarations (單例模式) / Object expressions (匿名內部類)/ Companion Objects
下一篇
[Day 15] Kotlin Interface
系列文
Android 菜鳥村-開發基礎 30篇32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言