Kotlin 是如何避免空指针问题的
在谈Kotlin的优势的时候,大家都会想到空指针安全这一点,那么Kotlin又是如何避免这些问题的呢?下面从Kotlin的一些语法规则上给出介绍。
可空类型
默认声明的变量是不能为 null 的,如果要使变量能为 null, 需要添加 ?操作符。例如:
val name: String = null // 编译错误
var name = "harry"
name = null // 编译错误
// 正确的写法
var name: String? = null
var name: String? = "harry"
name = null
同样, 方法的返回值,如果可能返回空,也要加 ?。
fun test(): String? = if ... else null
安全空访问
智能类型转换是一个相当好的特点,可以安全访问可空变量。例如:
var name: String? = "harry"
if (name != null) {
println(name.length)
}
但是,考虑到多个 null 检测,代码的可读性就变差。例如:
class Country(val name: String)
class City(val name: String, val country: Country?)
class Persion(val name: String, val city: City?)t
fun getCountryName(persion: Persion?): String? {
var countryName: String? = null
if (persion != null) {
val city = persion.city
if (city != null) {
val country = city.conutry
if (country != null) {
countryName = country.name
}
}
}
return countryName
}
嵌套的 null 检测, 代码可读性较差, Kotlin提供了简明的写法 ?。例如:
fun getCountryName(persion: Persion?) = persion?.city?.country?.name
非空断言
有时候,要将可空的变量转成非空的, 常见于Java, 我们知道变量是不可能为 null 的, 可以用非空断言 !!。例如:
val nullableString: String? = "hello world"
val string: String = nullableString!!
var name: String? = null
name = "jason"
val len = name!!.length
Elvis操作
Java里面, 有个三元操作?:, 实现 if … else … 的赋值。Kotlin 也有这个操作符, 但是用法不一样,例如:
val nullableName: String? = ...
val name: String = nullableName ?: "default_name"
如上代码意思了, 如果 nullableName 为 null, 就赋值 “default_name”。?:主要用于如果变量为 null就设置默认值。
安全类型转换
如果想安全地进行类型转换, 当转换失败时结果 null, 这种情况可用 as?。
val location: Any = "London"
val safeString: String? = location as? String
val safeInt: Int? = location as? Int
原理
为了更好的理解Kotlin空指针的原理。下面来看一下Kotlin是如何利用工具给开发者在编译前给出提示的。 以下面的Java判断空值方法为例:
public void foo(Bar bar) { /*…*/ }
对于这样一个典型的方法,如果传入的参数为null,那么通常的处理方式是检查输入:
public void foo(Bar bar) {
if (bar == null)
throw IllegalArgumentException(); /*…*/
}
如果调用该方法时传入了null,那么它会抛出异常,并提供有用的信息。但这要到运行的时候才能看到。如果方法定义本身就能明确表达不接受null参数的意图就好了。于是,上述代码可以进一步改进为:
public void foo(@NotNull Bar bar) {
if (bar == null)
throw IllegalArgumentException() /*…*/
}
如此一来,像IntelliJ IDEA这样的工具在检测到调用者可能传入null时就会提醒开发者。这样的代码没错,但就是有点啰嗦。 Kotlin采用了一种不同的null处理方式。它对可空类型和不可空类型作了区分,可空的类型后面会跟一个问号,比如Bar?,而Bar类型的变量则不可为空。于是,在Kotlin中,上述Java代码就变成了下面这样:
public fun foo(bar : Bar) { /*…*/ }
Kotlin非常简洁且富有表现力。这从上面的例子可见一斑。
- AI加持下的假肢将会越来越聪明
- 通过几个Hello World感受.NET Core全新的开发体验
- ASP.NET MVC三个重要的描述对象:ControllerDescriptor
- 基于自制数据集的MobileNet-SSD模型训练
- .NET Core采用的全新配置系统[1]: 读取配置数据
- ASP.NET MVC三个重要的描述对象:ActionDescriptor
- 升级比特币区块链后,以特币已叩响成功的大门
- .NET Core采用的全新配置系统[2]: 配置模型设计详解
- 采用双拼域名meicai.cn的美菜网融资4.5亿美元
- 区块链技术或将迎来突破性进展,以特币未来生机勃勃
- 配置多个网卡的OpenStack VM
- .NET Core采用的全新配置系统[3]: “Options模式”下的配置是如何绑定为Options对象
- 游戏用户中心开发
- .NET Core采用的全新配置系统[4]: “Options模式”下各种类型的Options对象是如何绑定的?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 使用MySQL Keyring 的 SECRET类型密钥执行非对称加密
- node egg 实现跨域
- 使用Markdown画流程图
- HBase NotServingRegionException
- Flink SQL 写入 Hive表的性能问题
- 文件系统索引extent 和 bitmap区别
- MySQL的Bugs
- 对复制实施主键约束
- MySQL如何管理客户端的连接?
- 鸿蒙 Ability 讲解(页面生命周期、后台服务、数据访问)
- MySQL如何管理客户端连接?线程池篇
- 让python装饰器不再晦涩难懂
- Android开发3年,九月份面试12家大厂跳槽成功,我有一些面试经验想分享给你们
- MySQL的防火墙功能
- Java中线程池的参数有几个?