亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

小談Kotlin的空處理的使用

2024-07-21 23:03:52
字體:
來源:轉載
供稿:網友

近來關于 Kotlin 的文章著實不少,Google 官方的支持讓越來越多的開發者開始關注 Kotlin。不久前加入的項目用的是 Kotlin 與 Java 混合開發的模式,紙上得來終覺淺,終于可以實踐一把新語言。 本文就來小談一下 Kotlin 中的空處理。

一、上手的確容易

先扯一扯 Kotlin 學習本身。

之前各種聽人說上手容易,但真要切換到另一門語言,難免還是會躊躇是否有這個必要?,F在因為工作關系直接上手 Kotlin,感受是 真香(上手的確容易) 。

首先在代碼閱讀層面,對于有 Java 基礎的程序員來說閱讀 Kotlin 代碼基本無障礙,除去一些操作符、一些順序上的變化,整體上可以直接閱讀。

其次在代碼編寫層面,僅需要改變一些編碼習慣。主要是:語句不要寫分號、變量需要用 var 或 val 聲明、類型寫在變量之后、實例化一個對象時不用 “new” …… 習慣層面的改變只需要多寫代碼,自然而然就適應了。

最后在學習方式層面,由于 Kotlin 最終都會被編譯成字節碼跑在 JVM 上,所以初入手時完全可以用 Java 作為對比。比如你可能不知道 Kotlin 里 companion object 是什么意思,但你知道既然 Kotlin 最終會轉成 jvm 可以跑的字節碼,那 Java 里必然可以找到與之對應的東西。

Android Studio 也提供了很方便的工具。選擇菜單 Tools -> Kotlin -> Show Kotlin Bytecode 即可看到 Kotlin 編譯成的字節碼,點擊窗口上方的 “Decompile” 即可看到這份字節碼對應的 Java 代碼。—— 這個工具特別重要,假如一段 Kotlin 代碼讓你看得云里霧里,看一下它對應的 Java 代碼你就能知道它的含義。

當然這里僅僅是說上手或入門(僅入門的話可以忽略諸如協程等高級特性),真正熟練應用乃至完全掌握肯定需要一定時間。

二、針對 NPE 的強規則

有些文章說 Kotlin 幫開發者解決了 NPE(NullPointerException),這個說法是不對的。 在我看來,Kotlin 沒有幫開發者解決了 NPE (Kotlin: 臣妾真的做不到?。?,而是通過在語言層面增加各種強規則,強制開發者去自己處理可能的空指針問題,達到盡量減少(只能減少而無法完全避免)出現 NPE 的目的。

那么 Kotlin 具體是怎么做的呢?別著急,我們可以先回顧一下在 Java 中我們是怎么處理空指針問題的。

Java 中對于空指針的處理總體來說可以分為“防御式編程”和“契約式編程”兩種方案。

“防御式編程”大家應該不陌生,核心思想是不信任任何“外部”輸入 —— 不管是真實的用戶輸入還是其他模塊傳入的實參,具體點就是 各種判空 。創建一個方法需要判空,創建一個邏輯塊需要判空,甚至自己的代碼內部也需要判空(防止對象的回收之類的)。示例如下:

public void showToast(Activity activity) {  if (activity == null) {    return;  }    ......}

另一種是“契約式編程”,各個模塊之間約定好一種規則,大家按照規則來辦事,出了問題找沒有遵守規則的人負責,這樣可以避免大量的判空邏輯。Android 提供了相關的注解以及最基礎的檢查來協助開發者,示例如下:

public void showToast(@NonNull Activity activity) {  ......}

在示例中我們給 Activity 增加了 @NonNull 的注解,就是向所有調用這個方法的人聲明了一個約定,調用方應該保證傳入的 activity 非空。當然聰明的你應該知道,這是一個很弱的限制,調用方沒注意或者不理會這個注解的話,程序就依然還有 NPE 導致的 crash 的風險。

回過頭來, 對于 Kotlin,我覺得就是一種把契約式編程和防御式編程相結合且提升到語言層面的處理方式。 (聽起來似乎比 Java 中各種判空或注解更麻煩?繼續看下去,你會發現的確是更麻煩……)

在 Kotlin 中,有以下幾方面約束:

在聲明階段,變量需要決定自己是否可為空,比如 var time: Long? 可接受 null,而 var time: Long 則不能接受 null。

在變量傳遞階段,必須保持“可空性”一致,比如形參聲明是不為空的,那么實參必須本身是非空或者轉為非空才能正常傳遞。示例如下:

fun main() {    ......    // test(isOpen) 直接這樣調用,編譯不通過    // 可以是在空檢查之內傳遞,證明自己非空    isOpen?.apply {       test(this)    }    // 也可以是強制轉成非空類型    test(isOpen!!)  }    private fun test(open: Boolean) {    ......  }

在使用階段,需要嚴格判空:

var time: Long? = 1000   //盡管你才賦值了非空的值,但在使用過程中,你無法這樣:   //time.toInt()   //必須判空   time?.toInt()

總的來說 Kotlin 為了解決 NPE 做了大量語言層級的強限制,的確可以做到減少 NPE 的發生。但這種既“契約式”(判空)又“防御式”(聲明空與非空)的方案會讓開發者做更多的工作,會更“麻煩”一點。

當然,Kotlin 為了減少麻煩,用 “?” 簡化了判空邏輯 —— “?” 的實質還是判空,我們可以通過工具查看 time?.toInt() 的 Java 等價代碼是:

if (time != null) {  int var10000 = (int)time;}

這種簡化在數據層級很深需要寫大量判空語句時會特別方便,這也是為什么 雖然邏輯上 Kotlin 讓開發者做了更多工作,但寫代碼過程中卻并沒有感覺到更麻煩。

三、強規則之下的 NPE 問題

在 Kotlin 這么嚴密的防御之下,NPE 問題是否已經被終結了呢?答案當然是否定的。在實踐過程中我們發現主要有以下幾種容易導致 NPE 的場景:

1. data class(含義對應 Java 中的 model)聲明了非空

例如從后端拿 json 數據的場景,后端的哪個字段可能會傳空是客戶端無法控制的,這種情況下我們的預期 必須是 每個字段都可能為空,這樣轉成 json object 時才不會有問題:

data class User(    var id: Long?,    var gender: Long?,    var avatar: String?)

假如有一個字段忘了加上”?”,后端沒傳該值就會拋出空指針異常。

2. 過分依賴 Kotlin 的空值檢查

private lateinit var mUser: User...private fun initView() { mUser = intent.getParcelableExtra<User>("key_user")}

在 Kotlin 的體系中久了會過分依賴于 Android Studio 的空值檢查,在代碼提示中 Intent 的 getParcelableExtra 方法返回的是非空,因此這里你直接用方法結果賦值不會有任何警告。但點擊進 getParcelableExtra 方法內部你會發現它的實現是這樣的:

public <T extends Parcelable> T getParcelableExtra(String name) {    return mExtras == null ? null : mExtras.<T>getParcelable(name);  }

內部的其他代碼不展開了,總之它是可能會返回 null 的,直接賦值顯然會有問題。

我理解這是 Kotlin 編譯工具對 Java 代碼檢查的不足之處, 它無法準確判斷 Java 方法是否會返回空就選擇無條件信任,即便方法本身可能還聲明了 @Nullable 。

3. 變量或形參聲明為非空

這點與第一、第二點都很類似,主要是使用過程中一定要進一步思考傳遞過來的值是否真的非空。

有人可能會說,那我全部都聲明為可空類型不就得了么 —— 這樣做會讓你在使用該變量的所有地方都需要判空,Kotlin 本身的便利性就蕩然無存了。

我的觀點是不要因噎廢食,使用時多注意點就可以避免大部分問題。

4. !! 強行轉為非空

當將可空類型賦值給非空類型時,需要有對空類型的判斷,確保非空才能賦值(Kotlin 的約束)。

我們使用 !! 可以很方便得將“可空”轉為“非空”, 但可空變量值為 null,則會 crash 。

因此使用上建議在確保非空時才用 !! :

param!!

否則還是盡量放在判空代碼塊里:

param?.let { doSomething(it) }

四、實踐中碰到的問題

從 Java 的空處理轉到 Kotlin 的空處理,我們可能會下意識去尋找對標 Java 的判空寫法:

if (n != null) { //非空如何 } else { //為空又如何}

在 Kotlin 中類似的寫法的確有,那就是結合高階函數 let、apply、run …… 來處理判空,比如上述 Java 代碼就可以寫成:

n?.let { //非空如何} ?: let { //為空又如何}

但這里有幾個小坑。

1. 兩個代碼塊不是互斥關系

假如是 Java 的寫法,那么不管 n 的值怎樣,兩個代碼塊都是互斥的,也就是“非黑即白”。但 Kotlin 的這種寫法不是(不確定這種寫法是否是最佳實踐,假如有更好的方案可以留言指出)。

?: 這個操作符可以理解為 if (a != null) a else b ,也就是它之前的值非空返回之前的值,否則返回之后的值。

而上面代碼中這些高階函數都是有返回值的,詳見下表:

 

函數 返回值
let 返回指定 return 或函數里最后一行
apply 返回該對象本身
run 返回指定 return 或函數里最后一行
with 返回指定 return 或函數里最后一行
also 返回該對象本身
takeIf 條件成立返回對象本身,不成立返回 null
takeUnless 條件成立返回 null,不成立返回該對象本身

 

假如用的是 let, 注意看它的返回值是“指定 return 或函數里最后一行”,那么碰到以下情況:

val n = 1var a = 0n?.let { a++ ... null //最后一行為 null} ?: let { a++}

你會很神奇地發現 a 的值是 2,也就是 既執行了前一個代碼塊,也執行了后一個代碼塊 。

上面這種寫法你可能不以為然,因為很明顯地提醒了諸位需要注意最后一行,但假如是之前沒注意這個細節或者是下面這種寫法呢?

n?.let { ... anMap.put(key, value) // anMap 是一個 HashMap} ?: let { ...}

應該很少人會注意到 Map 的 put 方法是有返回值的,且可能會返回 null。那么這種情況下很容易踩坑。

2. 兩個代碼塊的對象不同

以 let 為例,在 let 代碼塊里可以用 it 指代該對象(其他高階函數可能用 this,類似的),那么我們在寫如下代碼時可能會順手這樣寫:

activity { n?.let { it.hashCode() // it 為 n } ?: let { it.hashCode() // it 為 activity } }

結果自然會發現值不一樣。前一個代碼塊 it 指代的是 n,而后一個代碼塊里 it 指代的是整個代碼塊指向的 this。

原因是 ?: 與 let 之間是沒有 . 的,也就是說 后一個代碼塊調用 let 的對象并不是被判空的對象,而是 this 。(不過這種場景會出錯的概率不大,因為在后一個代碼塊里很多對象 n 的方法用不了,就會注意到問題了)

后記

總的來說切換到 Kotlin 還是比預期順利和舒服,寫慣了 Kotlin 后再回去寫 Java 反倒有點不習慣。今天先寫這點,后面有其他需要總結的再分享。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久精品在线观看| 久久青草福利网站| …久久精品99久久香蕉国产| 九九视频直播综合网| 国产亚洲精品一区二区| 亚洲女同性videos| 国产成人精品一区二区三区| 日本国产精品视频| 亚洲乱码av中文一区二区| 国产91精品久久久| 国产欧美一区二区| 亚洲国产婷婷香蕉久久久久久| 久久99久久久久久久噜噜| 91九色精品视频| 亚洲欧美日韩久久久久久| 欧美精品成人在线| 国内精品一区二区三区四区| 国产精品视频最多的网站| 国产丝袜一区二区三区| 国产欧美在线播放| 精品自拍视频在线观看| 亚洲一二三在线| 亚洲美女性生活视频| 不卡av在线播放| 日韩成人高清在线| 97视频在线看| 最好看的2019年中文视频| 欧美理论电影网| 尤物yw午夜国产精品视频| 欧美成人性色生活仑片| 97精品视频在线播放| 综合久久五月天| 亚洲视频欧洲视频| 国产精品一区专区欧美日韩| 亚洲精品www久久久久久广东| 国产主播在线一区| 日韩av中文在线| 夜夜嗨av一区二区三区四区| 欧美精品制服第一页| 国产精品高清免费在线观看| 2019国产精品自在线拍国产不卡| 在线观看久久久久久| 国产精品在线看| 日韩av中文字幕在线| 国产精品视频yy9099| 国产精品高潮粉嫩av| 97久久精品人人澡人人爽缅北| 奇米一区二区三区四区久久| 国产精品色视频| 高清日韩电视剧大全免费播放在线观看| 日本三级韩国三级久久| 国产精品盗摄久久久| 在线观看日韩www视频免费| 欧美日韩精品在线视频| 午夜精品一区二区三区av| 国产专区欧美专区| 日韩精品免费看| 免费成人高清视频| 欧美成人h版在线观看| 亚洲欧美日韩在线高清直播| 欧美丰满少妇xxxxx做受| 欧美激情亚洲精品| 91av在线播放视频| 一区二区三区视频在线| 日本成人精品在线| 一本色道久久88亚洲综合88| 日韩黄在线观看| 狠狠操狠狠色综合网| 欧美在线一级va免费观看| 丝袜美腿亚洲一区二区| 亚洲区中文字幕| 欧洲精品毛片网站| 97国产在线观看| 国产91精品久久久| 久久伊人91精品综合网站| 亚洲日本中文字幕免费在线不卡| 91精品综合视频| 亚洲精品suv精品一区二区| 中文字幕欧美亚洲| 欧美剧在线观看| 欧美亚洲成人网| 超薄丝袜一区二区| 68精品久久久久久欧美| 久久久女女女女999久久| 国色天香2019中文字幕在线观看| 国产欧美精品久久久| 日韩欧美亚洲范冰冰与中字| 久久精品这里热有精品| 成人信息集中地欧美| 欧美最猛性xxxxx免费| 亚洲欧美日韩国产中文专区| 国产精品成人aaaaa网站| 成人女保姆的销魂服务| 久久久久久久一区二区| 国外成人在线直播| 欧美日韩在线观看视频小说| 97在线看福利| 精品露脸国产偷人在视频| 成人黄色激情网| 欧美日韩成人在线视频| 91chinesevideo永久地址| 91免费在线视频网站| 欧美性xxxx极品hd满灌| 亚洲精品v欧美精品v日韩精品| 亚洲一级黄色av| 亚洲欧美综合精品久久成人| 亚洲国产精品字幕| 亚洲女人天堂成人av在线| 国产欧美精品日韩精品| 色综合久久天天综线观看| 久久精品99久久久香蕉| 久久精品一偷一偷国产| 国产在线不卡精品| 亚洲成人黄色网址| 色狠狠久久aa北条麻妃| 久久人人爽人人爽人人片亚洲| 国产成人精品a视频一区www| 欧美限制级电影在线观看| 激情懂色av一区av二区av| 国产精品美女久久| 国产欧美最新羞羞视频在线观看| 国产成人一区二| 成人黄色av免费在线观看| 97久久久免费福利网址| 精品日韩美女的视频高清| 国产精品mp4| 欧美激情国产高清| 色综合久久88色综合天天看泰| 日韩av在线免播放器| 成人免费视频网址| 91精品国产综合久久香蕉922| 亚洲欧美国产视频| 久久精品99久久香蕉国产色戒| 全色精品综合影院| 亚洲已满18点击进入在线看片| 成人在线播放av| 国产日韩在线观看av| 亚洲精品福利在线| 亚洲国产美女精品久久久久∴| 亚洲精品中文字| 国产视频久久久久| 欧美激情极品视频| 日韩精品视频三区| 国产精品国产三级国产aⅴ9色| 久久大大胆人体| 成人性生交大片免费看视频直播| 亚洲小视频在线| 欧美日韩另类视频| 久久久www成人免费精品张筱雨| 欧美午夜影院在线视频| 国产精品视频资源| 热re91久久精品国99热蜜臀| 欧美大片在线看| 欧美大片免费观看在线观看网站推荐| 亚洲最新av网址| 亚洲成人黄色在线| 久久久精品中文字幕| 欧美国产精品人人做人人爱| www.亚洲一区| 欧洲一区二区视频| 欧美在线视频观看| 久久综合网hezyo| 亚洲资源在线看| 国产精品视频网|