null安全可以说是Kotlin语言对Java的重大改进之一,这样可以避免Java变成时令人恐惧的NullPointerExcept(简称NPE)。
Kotlin 类型系统的设计目标就是希望消除代码中 null 引用带来的危险。
Kotlin 的类型系统致力于从我们的代码中消除 NullPointerException. 只有以下情况可能导致 NPE:
-
明确调用 throw NullPointerException()
-
使用 !! 操作符, 详情见后文使用 !! 操作符, 详情见后文
-
外部的 Java 代码导致这个异常外部的 Java 代码导致这个异常
-
初始化过程中存在某些数据不一致 (在构造器中使用了未初始化的 this)初始化过程中存在某些数据不一致 (在构造器中使用了未初始化的 this)
下面来学习下Kotlin的null安全的相关知识点!
先看下面的简单例子
fun main(args: Array<String>) {
var str = "ouyangpeng"
var sum1: Int = str.toIntOrNull()
var sum2: Int? = str.toIntOrNull()
println("sum = $sum1")
println("sum2 = $sum2")
第7行声明sum1的类型是Int,第8行声明的sum2的类型是Int?。
程序中第7行代码无法通过编译,第8行代码可以通过编译。
其中 Int? 就是可空类型,这种类型的变量可接受Int值和null;
而Int类型的变量只接受Int值,不能接受null。
var n = str.toIntOrNull()
Kotlin对可空类型进行了限制:如果不加任何处理,可控类型不允许直接调用方法、访问属性。
因此,通过可控类型与非空类型的区分,Kotlin即可在程序中避免空指针异常。例如如下代码:
var n = str.toIntOrNull()
var aStr: String = "oyp"
var bStr: String? = "oyp"
aStr = null
bStr = null
println(aStr.length)
println(bStr.length)
上面代码定义了aStr 和 bStr两个变量,
其中aStr是非空的String类型,因此aStr变量不允许赋值为null;
而bStr是可空类型,bStr变量允许被赋值为null。
因此程序可以调用aStr的方法或熟悉,但aStr变量的值不可能为null,因此可以避免NPE的出现。
而由于Kotlin对可空类型的限制:如果不加任何处理,可控类型不允许直接调用方法、访问属性。 因此程序不能直接调用bStr的方法或属性,这样也可以避免NPE的出现。
可空类型的变量不允许直接调用方法或熟悉,单可以先判断该变量不为null,然后再调用该变量的方法或熟悉。如下代码所示:
var b: String? = "oyp"
var len = if (b != null) b.length else -1
println("b的长度为 $len")
b = null
if (b != null && b.length > 0){
println("b的长度为 ${b.length}")
} else {
println("b为空字符串")
上面程序定义了String?(可控类型)的变量b,因此程序不能直接调用b的方法或熟悉。Kotlin要求程序先判断b不为null,然后在该条件下调用b的方法或属性。
因为 Boolean? 类型,可以接受 true false null 三个值, 因此 对Boolean? 类型变量判断时,要显示与 true false 的值做比较
var bParam: Boolean? = null
if (bParam == true) {
println("为真")
if (bParam) {
println("为真")
上面代码,下面的if(bParam) 直接会导致编译器报错 Type mismatch: inferred type is Boolean? but Boolean was expected
。这是因为Kotlin的if条件必须为Boolean类型,而Boolean?与Boolean本质上是两种不同的类型,因此编译器会报错。
先看下简单的例子,使用 “?.” 安全调用来访问可空类型的属性
fun main(args: Array<String>) {
// 安全调用 如果 b 不等于null,则返回b的长度,如果b为null,则返回null,不会导致NPE
var b: String? = "oyp"
println(b?.length) // 3
b = null
println(b?.length) // null
上面的程序中,变量b的类型为String? (可空类型),因此程序使用 “?.” 安全调用来访问b的length属性,当b为null的时候,也不会引发NPE,而是返回null。
其实翻译成普通的语句就是
if (b == null) {
println(null)
} else {
println(b.length)
如果不使用安全调用的话,会报错 Error:(10, 14) Kotlin: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?

user?.dog?.name
上面代码表示安全获取user的dog的name的属性值,如果user或者user.dog 为null,整个表达式将返回null。
- 与let全局函数结合使用
安全调用还可以与let全局函数结合使用,如下所示
var myArr: Array<String?> = arrayOf("oyp", null, "csdn", "xtc")
for (item in myArr) {
item?.let { println(it) }
上面代码使用安全调用来调用let函数,这样只有当item元素不为null才会执行let函数。
Elvis运算也是一个小技巧,其实就是if else的简化写法。
fun main(args: Array<String>) {
var b: String? = "oyp"
var len1 = if (b != null) b.length else -1
println(len1)
b = null
var len2 = b?.length ?: -1
println(len2)
上面代码第6行使用了传统的if分支来进行判断,当b不为null时返回b.length,否则返回-1;
第13行代码使用了 “?:"运算符,该运算符就是Elvis,它的含义是:如果“?:"左边表达式不为null,则返回左边表达式的值,否则返回“?:"右边表达式的值。
使用 Elvis运算符
若第一个运算数不为null,运算结果就是第一个运算数;
若第一个运算数为null,运算结果就是第二个运算数。
由此可见,“?:”其实就是if分支的简化写法。
扩展一下:由于Kotlin的return和throw都属于表达式,因此它们也可以用在Elvis运算符的右边。
val parent = user.getParent() ?: return null
val name = user.getName() ?: throw IllegalArgumentException ("name expected")
强制调用是为NPE“爱好者”准备的,比如你想不管变量是否为null,程序都直接调用该属性的方法或属性。Kotlin也为这种用法提供了支持,用“!!.”即可强制调用可空变量的方法或属性,这样强制调用可能引发NPE。
fun main(args: Array<String>) {
var b: String? = "oyp"
println(b!!.length)
b = null
println(b!!.length)
var myArr: Array<String?> = arrayOf("oyp", null, "csdn", "xtc")
for (item in myArr) {
item!!.let { println(it) }
上面代码,将 安全调用 ?. 改为 强制调用 !!. 当 b为null的时候,b!!.length
就会引发NPE。
let函数里面的,不管item元素是否为null,强制调用的话也会导致NPE。
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:https://blog.csdn.net/qq446282412/article/details/85209203
☞ 本人QQ: 3024665621
☞ QQ交流群: 123133153
☞ github.com/ouyangpeng
☞ oypcz@foxmail.com
如果本文对您有所帮助,欢迎您扫码下图所示的支付宝和微信支付二维码对本文进行打赏。
【CSDN 编者按】Kotlin 和 Java 是如何解决 Null 问题?本文作者分享了解决思路。原文链接:https://blog.frankel.ch/null-safety-java-vs-kotlin/未经授权,禁止转载!作者 |Nicolas Fränkel 责编 |弯月出品 | CSDN(ID:CSDNnews)在本文中,我想讨论一下 Kotlin 和 Java 是如何解决 ...
文章目录背景Kotlin 的优势1. 用于服务端开发2. 用于 JavaScript3. 开发 Android 应用第一个 Kotlin 程序分析:Kotlin 语言的特点Kotlin 语言中的注释
Kotlin 是 JetBrains 在 2011 年推出的一门全新编程语言,最早被设计运行在 JVM 上 , 使用 Kotlin 编写的程序会被编译成 Java 的字节码文件。Kotlin 可以和现在的 Java 语言包 100% 兼容, 而且 Kotlin 代码比 Java 代码更简洁、更富有表现力
这里写目录标题一、空安全相关1.1 定义一个可空类型的变量1.2 安全调用操作符——?.1.3 带let的安全调用1.4 ?:操作符1.5 非空断言操作符——!!操作符1.6 安全的类型转换——as?操作符1.7 类型检测及自动类型转换——is运算符
一、空安全相关
1.1 定义一个可空类型的变量
定义一个可空类型的变量的格式为:修饰符 变量名 : 类型? = 值,kotlin默认定义的变量不能为空
// 定义一个不可为空的变量,用var修饰的变量可以被重新赋值,用val修饰的变量则不能,但是不能
val name="Jimmy's friend"
var index=name.indexOf("\'")
val str=name.substring(0 until index )
println(str)
Jimmy
这没啥好说的,和java差不
Kotlin 的类型系统致力于从我们的代码中消除 NullPointerException. 只有以下情况可能导致 NPE:
明确调用 throw NullPointerException()使用 !! 操作符, 详情见后文外部的 Java 代码导致这个异常初始化过程中存在某些数据不一致 (在构造器中使
null安全可以说是Kotlin语言对Java的重大改进之一,这样可以避免Java编程时令人恐惧的“NullPointerException”(简称:NPE)。但话说回来,null安全不过是各种现代语言玩剩下的东西。1 非空类型和可空类型下面先看一个简单的例子。程序清单:codes\02\2.8\NullableTest.ktfun main(args: Array<String>) ...
学安卓第一天
跟着 第一行代码 敲了一个取最大值的函数,在main方法里运行时提示
Type mismatch: inferred type is Int but Unit was expected
仔细看了一下,原来是方法参数后面我忘了加返回值,补上就解决了
Kotlin 类型系统的设计目标就是希望消除代码中null引用带来的危险。
Kotlin 的类型系统致力于从我们的代码中消除NullPointerException. 只有以下情况可能导致NPE:
明确调用 throw NullPointerException()
使用 !! 操作符, 详情见后文
外部的 Java 代码导致这个异常
初始化过程中存在某些数据不一致 (在构造器中使用了未初始化的 this)
在 Kotlin 中, 类型系统明确区分可以指向null的引用 (可为null引用) 与不可以指向
// @file:JvmName("Stu") 注意:必须写在 包名的外面
fun getStudentNameValueInfo(str : String) = println(str)
fun main() {}
/* 背后生成的代码:
public final class TestKt {