本文是對<<Kotlin in Action>>
的學習筆記,若是須要運行相應的代碼能夠訪問在線環境 try.kotlinlang.org,這部分的思惟導圖爲: java
當咱們在聲明方法時,若是容許在這個方法被調用的時候傳給它null
的實參,則須要顯示地 在類型名稱後面加上問號來標記它: 安全
null
引用,而全部
常見類型默認都是非空的,除非顯示地把它標記爲可空。
當你有一個可空類型的值,對它的操做也會受到限制:框架
針對上面的第一點,最重要的操做就是和null
進行比較,一旦進行了比較操做,編譯器就會記住,而且在此次比較發生的做用域內把這個值當作非空來對待,而後才能夠 調用它的方法,下面是最容易理解的作法,後面咱們將會看到更加簡潔的實現: ide
類型就是數據的分類,決定了該類型可能的值,以及該類型的值上能夠完成的操做。函數
下面咱們分析一下String
類型的變量,在Java
中這樣的變量有兩種值:分別是String
的實例和null
:工具
instanceof
操做符會告訴你null
不是String
String
實例容許你調用它的任何方法,而null
值只會容許很是有限的操做這說明Java
的類型系統在這種狀況下不能很好地工做,即便變量擁有聲明的類型String
你依然沒法知道能對該變量的值作些什麼,除非作額外的檢查。學習
Kotlin
的可空類型爲這類問題提供了全面的解決方案,區分開可空類型和非空類型 使事情變得明朗,哪些對值的操做是容許的,哪些操做會致使運行時異常並所以被中止。this
安全調用運算符?.
把一次null
檢查和一次方法調用合併成一個操做。 spa
安全調用不光能夠調用方法,也能用來訪問屬性。 3d
Kotlin
有方便的運算符來提供代替null
的默認值,它被稱做Elvis
運算符,咱們在2.3
的基礎上增長紅框內的代碼,使得name
爲空的時候將返回值設爲Unknow
:
Elvis
接收兩個運算數:若是第一個運算數(
name
)不爲
null
,運算結果就是第一個運算數;若是第一個運算數爲
null
,運算結果就是第二個運算數。
安全轉換運算符會嘗試把值轉換成指定的類型,若是類型不合適就返回null
,下面的例子中,先判斷傳入的參數是不是Person
類型,若是不是,那麼就直接返回false
,而在以後的代碼中智能轉換就會生效,編譯器肯定了變量otherPerson
值的類型是Person
,咱們就能夠直接訪問它的name
屬性。
非空斷言 是Kotlin
提供給你的最簡單直率的處理可空類型的工具,它使用!!
表示,能夠把任何值轉換成非空類型,若是對null
值作非空斷言,則會拋出異常,例以下面的示例代碼:
當可空參數最多見的一種用法就是被傳遞給一個接收非空參數的函數以前,須要進行相應的檢查。好比說下面這個sendEmailTo
函數,它接收一個String
類型的參數並向這個地址發送一封郵件。
假如咱們傳遞給它一個空的emailName
,那麼在編譯時就會拋出異常:
爲了解決上面的問題,咱們應當在調用函數前確保該變量不爲空:
下面,咱們再來看一下若是經過let
解決上面的問題,let
函數作的事情就是把一個調用它的對象變成lambda
表達式的參數,若是結合安全調用語法,它能有效地把調用let
函數的可空對象,轉變成非空類型:
let
函數只在
nullEmail
的值非空時才被調用,因此就能在
lambda
中把
nullEmail
當作非空的實參來使用。
不少框架都會在對象實例建立後用專門的方法來初始化對象,例如Activity
的onCreate
方法,可是你不能在構造方法中徹底放棄非空屬性的初始化器,僅僅在一個特殊的方法裏初始化它,若是某個屬性是非空類型,那麼必須在構造方法中提供非空的初始化值,不然你就必須使用可空類型。可是若是使用了可空類型,那麼該屬性的每次訪問都須要null
檢查或者!!
運算符。
name
屬性的時候,都須要經過安全調用運算符
?.
檢查後,才能調用
String
的方法,這是至關麻煩的。爲了解決這個問題,咱們能夠將
name
屬性聲明成能夠延遲初始化的。
var
,由於須要在構造方法外修改它的值,儘管它是非空類型,可是不須要在構造方法中初始化它,而若是在屬性被初始化前調用了它的方法,那麼會拋出下面的異常。
爲可空類型定義擴展函數時一種更強大的處理null
值的方式,能夠容許接收者爲null
的(擴展函數)調用,並在該函數中處理null
,而不是在確保變量不爲null
後再調用它的方法。
只有擴展函數能作到這點,普通成員方法的調用是經過對象實例分發的,所以實例爲null
時(成員方法)永遠不能被執行。
在Kotlin
標準庫中定義的isNullOfEmpty
就能夠由String?
類型的接收者調用:
isNullOfEmpty
的定義以下:
fun String?.isNullOfBlank() : Boolean = this == null || this.isBlank()
複製代碼
Kotlin
中全部泛型類和泛型函數的類型參數默認都是可空的,任何類型,包括可空類型在內,均可以替換類型參數。這種狀況下,使用類型參數做爲類型的聲明都容許爲null
,儘管類型參數T
沒有用問號結尾,因此咱們必須使用安全調用:
Java
的類型系統是不支持可空性的,那麼當你混合使用Kotlin
和Java
時會發生什麼呢?
有些時候,Java
代碼包含了可空性的信息,這些信息使用註解來表達。當代碼中出現了這樣的信息,Kotlin
就會使用它,所以Java
中的@Nullable String
被Kotlin
當作String
,而@NotNull String
就是String
,例如咱們在Java
中定義下面這個包含了@NotNull
註解的方法:
Kotlin
中調用這個方法並傳入可空類型,就會提示類型不匹配:
若是註解不存在時,Java
類型會變成Kotlin
中的 平臺類型。平臺類型本質上就是Kotlin
不知道可空性信息的類型,這意味着,你要像在Java
中同樣,對你在這個類型上作的操做負有所有責任,編譯器將會容許全部的操做。
當在Kotlin
中重寫Java
的方法時,能夠選擇把參數和返回類型定義成可空的,也能夠選擇把它們定義成非空的。例如,咱們來看一個Java
中的StringProcessor
接口:
public interface StringProcessor {
void process(String value);
}
複製代碼
Kotlin
中實現接口時使用不一樣的可空性:
class StringPrinter : StringProcessor {
override fun process(value: String) {
print(String)
}
}
class NullableStringPrinter : StringProcessor {
override fun process(value: String?) {
println(value ?: "Empty")
}
}
複製代碼