文獻地址:《null-safety》 首先要聲明,后續(xù)文字,都是個人愚見,歡迎討論指正。
為什么更新文章
有一段時間沒有寫技術文章了的,借口有很多,比如天太冷上海都下起了大雪,忙于業(yè)務... 等等,今天為什么想起來寫技術文章,只是因為下午開會,同事反饋說小組里面對 Kotlin 的認知,可能還是停留在 Java 的習慣上。就像你現(xiàn)在讓我去寫 mac ,我想可能我也會下意識的寫出個什么 xxxImpl 來。
為什么選擇這個話題
可是,既然要寫,為什么會選這個話題?可能隨便百度谷歌一搜索,就已經(jīng)有一大把關于這個話題的文章了的。我之所以選擇這個話題,我覺得 ? 這個符號,真的不是 簡單的 Null Safety 類型安全,又或者 永別了的 NPE 。什么時候使用 ?
? 到底是選擇問題前置還是問題后置? 是要和你后續(xù)程序設計層面` 考慮的。
漫漫長夜咱細聊
關于 Kotlin 的 可選性 optional 的語法使用,我在開頭已經(jīng)寫了鏈接,這里我就不做翻譯了的。optional 字面意思是可選的,這個是一個對于Java而言相對新的概念,代表一個東西可能有,也可能沒用。那么既然一個 屬性 或者 參數(shù) 表示了 optional 那么我們在設計的時候,就已經(jīng)認定它會存在 null 的情況,所以在后續(xù)使用的過程中需要自己額外判斷,當然你會說我這樣寫:
var group: Group? = null //類創(chuàng)建的時候,可為空
group?.child?.id?.... //把問題后置
確實沒錯,我們可以很任性的一直往后面 ?. 訪問后續(xù)的方法或屬性等然后進行一系列的操作。當然我個人也非常建議多使用 ?,這樣可以把問題后置。但我這里要說的,如果這個 group 是持有類或者方法必要的參數(shù),那么是否在初始化或者傳參的時候,就必須要求有值呢?
lateinit var group: Group //類創(chuàng)建的時候必須給初始化
fun updateGroup(group: Group) // 不接受參數(shù)為空,調用方如果為空會crash,把問題前置
到底是選擇問題前置還是問題后置,是依據(jù)情況而定。
問題前置可以及時的暴露問題,并且排查問題。
lateinit var imageView: ImageView
init {
imageView = findViewById(R.id.img) as! ImageView //如果id沒有找到,這里就會crash
}
}
但是選擇問題后置,聲明屬性的時候默認都是?可空,那么在findViewById的時候,就會逃避并且跳過 crash。
var imageView: ImageView ? = null
init {
imageView = findViewById(R.id.img) as? ImageView //如果id沒有找到,這里不會crash
}
}
可是后續(xù)某一些場景情況下,由于這種方式,更偏向于:我們主動告訴編譯器我并不是很care他是否有值,有值我就接著往后面操作,沒有值,你什么都不需要做,最終導致可能界面一塊空白,排查起來比較麻煩。又后者要拿一下view本身的屬性,代碼寫起來可能你也覺得有點痛苦。
imageView?.displayImage(....) //結果界面沒有顯示出來圖片,因為imageView為空
if(imageView?.enable?:false){
//....寫起來有點累
}
而問題后置,更適合于統(tǒng)一處理的情況。比如我有一個顯示圖片的方法:
//我有處理null異常情況的能力
fun ImageView.displayAvatarImage(url: String?) {
val url = url?:return
//....
}
上層并不需要每次都判斷一下圖片地址是否為空的情況,而是統(tǒng)一交給最后一個環(huán)節(jié)進行處理就可以了的。
這里其實可以再細聊引入另一個話題,初始化原則,這里就不做展開了的,可以參考這里:《init-keywords》,雖然是 Swift,但是從程序設計層面上,是可以借鑒的。
個人誠懇的愚見
無論是問題前置還是問題后置,個人建議,當訪問一些不確定的東西的時候,盡量使用?, is ,as? 等等,杜絕不加判斷的就直接!!訪問操作。 為了強化這個愚見,假設一個可選的類型,可以理解為是一個對象,對象里面有兩個值,一個是 none,一個是具體的 somevalue. 當你用?的時候,等價于你很保守的訪問了somevalue,但是如果你直接!!訪問操作,就等價于強制性的訪問value,但是 value 是 null,就會跟 Java 一樣的 NPE 的悲劇發(fā)生。說到這里我想引入一個解包的概念,也就是庖丁解牛,我們要去訪問一個可選類型,要把他拆開,此時:
? 等價于 “hi,你里面有數(shù)據(jù)嗎? 有的話給我,沒的話,我想退出代碼塊或者找別人去啦”
!! 等價于 “管你有沒有,我就是要找你拿數(shù)據(jù),結果臣妾做不到啊,我沒東西給你了的,只能NPE crash了的!”
Null Safety ???

聊了這么多,為什么一直沒有提到 Null Safety, 我想表達的觀點是:并不是把 Java covert to kotlin 就萬事大吉,就什么也不用做了的,就Null Safety了的。僅僅是編譯器幫忙做了一些累贅的編碼工作罷了(你可以看生成的.class,僅僅只是幫我們寫了判空的if else罷了),不要被這個名詞給蒙蔽了雙眼,當你偷懶的時候,那么抱歉,Null Safety 就是一個笑話,啟動起來照樣崩潰!