让你的 Kotlin 代码远离 !!

简评:优雅的运用 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 关键字。

private lateinit var mAdapter: RecyclerAdapter<Transaction>

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAdapter = RecyclerAdapter(R.layout.item_transaction)
} fun updateTransactions() {
mAdapter.notifyDataSetChanged()
}

要注意,访问未初始化的 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 检查很好的替代品,但有时我们会遇到更复杂的情况。比如:

if (mUserName != null && mPhotoUrl != null) {
uploadPhoto(mUserName!!, mPhotoUrl!!)
}

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

fun <T1, T2> ifNotNull(value1: T1?, value2: T2?, bothNotNull: (T1, T2) -> (Unit)) {
if (value1 != null && value2 != null) {
bothNotNull(value1, value2)
}
}

5. 使用 Elvis 运算符

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

fun getUserName(): String {
if (mUserName != null) {
return mUserName!!
} else {
return "Anonymous"
}
}

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

fun getUserName(): String {
return mUserName ?: "Anonymous"
}

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

6. 自定义崩溃信息

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

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

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

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

扩展阅读:

Kotlin 中关于 val 的一个小知识点

kotlin 代码习惯1的更多相关文章

  1. Typecho-Material主题不支持Kotlin代码高亮的解决方案

    Typecho-Material主题不支持Kotlin代码高亮的解决方案 Overview 最近通过Typecho搭建了一个Blog,采用了 Material主题,其他的都挺好,也挺喜欢这个主题,但是 ...

  2. 快速书写常见的 Kotlin 代码 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. 怎样从Java转换到Kotlin代码:现在就开始使用Kotlin(KAD 29)

    作者:Antonio Leiva 时间:Jul, 4, 2017 原文链接:https://antonioleiva.com/kotlin-from-java/ Kotlin最神奇特性之一是它能与Ja ...

  4. 注重代码习惯,Python零基础从这本书籍开始!

    笨办法学 Python是Zed Shaw 编写的一本Python入门书籍.适合对计算机了解不多,没有学过编程,但对编程感兴趣的朋友学习使用.这本书以习题的方式引导读者一步一步学习编 程,从简单的打印一 ...

  5. 改变你代码习惯的ES6

    最近读阮一峰老师的ES6标准入门,让我感觉到了ES6的强大之处,读书之余整理了一些笔记,因为边读边记录的,所以可能会比较杂乱. ECMAScript和Javascript的关系 1996年11月,Ja ...

  6. js-注释代码习惯

    功能块代码 /** * xxxx */ 定义的函数或方法 /* xxxx */ 调用了某个函数或方法 // <--xxx

  7. 300行Kotlin代码实现的区块链

    使用Kotlin实现的区块链基本逻辑! 源码地址 GitHub仓库 启动方式 启动参数添加 -Dserver.port=8080,启动不同的端口,模拟不同的节点. 假设目前启动了8080和8081两个 ...

  8. kotlin 代码格式

    与java 不同,代码顺序影响编译过程. { var a:Int = 1; init(){ a++; } //var a:Int = 1;  写在 init 之后不可用. }

  9. 论好的代码习惯的养成/做一个优雅的coder

    1.先说一下以前被滴滴大佬教育的事情: 以前写代码的时候,因为只需要取特定的几个字段,所以经常这么写 //Request $request for example $parameters = $req ...

随机推荐

  1. 【Jmeter自学】Linux环境下Jmeter运行

    ==================================================================================================== ...

  2. day5--装饰器函数的信息打印,迭代器,生成器,列表推导式,内置函数

    本文档主要内容: 一 装饰器函数的信息打印 二 迭代器 三 生成器 四 生成器表达式和列表推导式 五 内置函数 一 装饰器函数的信息打印 一个函数一旦被装饰器给装饰后,这个函数的信息使用原来的命令打印 ...

  3. win7 安装英文语言包

    因为某些英文程序字符显示不全,所以考虑把 win7 改为英文语言.直接下载英文语言包安装不成功,经过多次尝试和百度终于找到合适的办法. 下载 Vistalizator.exe, windows6.1- ...

  4. 学习excel的使用技巧一空格替换为0

    问题1  把excel表格中的空格  填充为0 方法1 选中CDE列    CRTL+F 查找空 替换为0 方法2 选中CDE列 CRTL+G 打开定位  点击条件定位  选择空值 点击确定  然后在 ...

  5. 5.分析mitmproxy的优势及工具mitmdump的使用(参照书籍)

    mitmproxy优势:功能和charles.fiddler相似,强大之处在于它的工具 mitmdump 可以直接对接python 对请求做处理. mitmdump使用 : 1.mitmdump是mi ...

  6. py库: jieba (中文词频统计) 、collections (字频统计)、WordCloud (词云)

    先来个最简单的: # 查找列表中出现次数最多的值 ls = [1, 2, 3, 4, 5, 6, 1, 2, 1, 2, 1, 1] ls = ["呵呵", "呵呵&qu ...

  7. 字符串流stringReader

    String info ="good good study day day up";StringReader stringReader = new StringReader(inf ...

  8. Django - session 会话跟踪技术

    1.session简介 |session 英 /'seʃ(ə)n/ 美 /'sɛʃən/ 基于cookies开发,将值存到服务端 写session 读session Session是服务器端技术,利用 ...

  9. java 使用jsoup处理html字符

    依赖的jar <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artif ...

  10. SQL Server CLR 使用 C# 自定义存储过程和触发器

    资源来源:https://www.cnblogs.com/Brambling/p/8016060.html SQL Server CLR 使用 C# 自定义存储过程和触发器   这一篇博客接着上一篇博 ...