让你的 Kotlin 代码远离 !!

原文:How to remove all !! from your Kotlin code

 

简评:优雅的运用 Kotlin 的 null safety 特性,而不要简单的直接用 !!。

 

对于 Null 的检查是 Kotlin 的特点之一。强制你在编码过程中考虑变量是否可为 null,因此可以避免很多在 Java 中隐藏的 NullPointerException。

但是,当你用插件直接将 Java 代码转换为 Kotlin 时,你会发现有很多 !! 在里面。但其实 !! 意味着「有一个潜在未处理的 KotlinNullPointerException 在这里」。

这里就介绍 6 个避免 !! 的方法:

1. 用 val 而不是 var

在 Kotlin 中 val 代表只读,var 代表可变。建议尽可能多的使用 val。val 是线程安全的,并且不需要担心 null 的问题。只需要注意 val 在某些情况下也是可变的就行了。

可以看看这里: Mutable vals in Kotlin

2. 使用 lateinit

有些情况我们不能使用 val,比如,在 Android 中某些属性需要在 onCreate() 方法中初始化。对于这种情况,Kotlin 提供了 lateinit 关键字。

 
  1. private lateinit var mAdapter: RecyclerAdapter<Transaction>

  2.  
  3. override fun onCreate(savedInstanceState: Bundle?) {

  4. super.onCreate(savedInstanceState)

  5. mAdapter = RecyclerAdapter(R.layout.item_transaction)

  6. }

  7.  
  8. fun updateTransactions() {

  9. mAdapter.notifyDataSetChanged()

  10. }

要注意,访问未初始化的 lateinit 属性会导致 UninitializedPropertyAccessException。

并且 lateinit 不支持基础数据类型,比如 Int。对于基础数据类型,我们可以这样:

private var mNumber: Int by Delegates.notNull<Int>()

3. 使用 let 函数

下面是 Kotlin 代码常见的编译错误:

许多开发者都会选择 quick-fix:

private var mPhotoUrl: String? = null

fun uploadClicked() {
    if (mPhotoUrl != null) {
        uploadPhoto(mPhotoUrl!!)
    }
}

但这里选择 let 函数是一个更优雅的解决方法:

private var mPhotoUrl: String? = null

fun uploadClicked() {
    mPhotoUrl?.let { uploadPhoto(it) }
}

4. 创建全局函数来处理更复杂的情况

let 是一个对于 null 检查很好的替代品,但有时我们会遇到更复杂的情况。比如:

 
  1. if (mUserName != null && mPhotoUrl != null) {

  2. uploadPhoto(mUserName!!, mPhotoUrl!!)

  3. }

你可以选择嵌套两个 let,但这样可读性并不好。这时你可以构建一个全局函数:

 
  1. fun <T1, T2> ifNotNull(value1: T1?, value2: T2?, bothNotNull: (T1, T2) -> (Unit)) {

  2. if (value1 != null && value2 != null) {

  3. bothNotNull(value1, value2)

  4. }

  5. }

5. 使用 Elvis 运算符

Elvis 运算符在 Groovy 和 PHP 等语言中都存在。对于当值可能为 null 的情况特别方便:

 
  1. fun getUserName(): String {

  2. if (mUserName != null) {

  3. return mUserName!!

  4. } else {

  5. return "Anonymous"

  6. }

  7. }

上面的代码就可以简化为:

 
  1. fun getUserName(): String {

  2. return mUserName ?: "Anonymous"

  3. }

为什么叫 Elvis 呢?因为 ?: 很像猫王的发型:

6. 自定义崩溃信息

如果我们使用 !!,那么当这个变量为 null 时,只会简单的抛出一个 KotlinNullPointerException。这时我们可以用 requireNotNull 或 checkNotNull 来附带异常信息,方便我们调试。

uploadPhoto(requireNotNull(intent.getStringExtra("PHOTO_URL"), { "Activity parameter 'PHOTO_URL' is missing" }))

总而言之,绝大多数情况下你都不需要 !!,可以用上面提到的 6 个技巧来消除 !!。这样能让代码更安全、更容易 debug 并且更干净。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值