让你的 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. 事件驱动架构 (Event-Driven Architecture,EDA) 简介

    EDA 是一种侧重于以生成/消费为基础的异步通信的架构模式.这主要对照于传统的基于线程的同步系统. EDA 是一种以事件 (event)为核心,提供事件产生,路由,消费已经结果回调等机制的架构模式. ...

  2. Postman用法,了解一下

    一.Postman的基础功能 二.接口请求流程 1. GET 请求 GET请求:点击Params,输入参数及value,可输入多个,即时显示在URL链接上, 所以,GET请求的请求头与请求参数如在接口 ...

  3. android开发 RecyclerView 瀑布列表布局

    1.写一个内容的自定义小布局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xm ...

  4. 学习笔记:ES6

    http://es6.ruanyifeng.com/ ECMAScript 6 https://frankfang.github.io/es-6-tutorials/ ES 6 新特性列表 2017- ...

  5. curd——5

    curd——5 SELECT area_id  FROM 16tree.ts_area  where pid=0; <?php //1可以防止注入$db = Yii::app()->db; ...

  6. Getting started with C# and GDAL

    Getting started with C# and GDAL http://vipassanaandenvironmentalinformatics.blogspot.jp/2013/03/get ...

  7. Nginx 设置负载均衡

    1. 在nginx配置文件目录下另外单独创建一个文件用于管理负载均衡配置,这里起名为 fzjh.conf vim /etc/nginx/fzjh.conf #在文件下添加以下内容 upstream m ...

  8. nosql数据库:mongodb,redis,memcached,其优缺点和使用应用场景

    1.mongodb (1)是文档型的非关系型数据库,使用bson结构.其优势在于查询功能比较强大,能存储海量数据,缺点是比较消耗内存. (2)一般可以用来存放评论等半结构化数据,支持二级索引. 适合存 ...

  9. ubuntu16.04搭建geodjango+postgresql+postgis的WebGIS框架(二))安装postgresql和postgis

    卸载老版本sudo dpkg --purge postgis postgresql-9.3-postgis1.安装postgresql sudo apt-cache search postgresql ...

  10. 解决Run As -> Java Application不能运行问题

    转自:https://breakshell.iteye.com/blog/467130 点 Run As -> Java Application 不能运行,报的错误如下: Plug-in org ...