Kotlin中?和!!的区别
很多同学刚上手使用Kotlin知道它有针对Java NullPointerException的管理,而在Kotlin中?和!!均是和NullPointerException有关系,可他们的区别到底是什么呢?为什么别人开发的项目中出现了好多"?",而我读起来却满脸问号。

不懂就问百度呀,确实有人解释它们的区别,比如:

这是输入"kotlin ?和!!"搜索到的百度第一条答案,确实这位说的没错。不过我觉得对于一个刚接触KT(Kotlin)的新手来说,他恐怕需要有汉语八级才能透彻理解这两句话的意思。
先阐述两个概念:
"?"加在变量名后,系统在任何情况不会报它的空指针异常。
"!!"加在变量名后,如果对象为null,那么系统一定会报异常!
先拿Java代码举个例子
ArrayList<String> myList = null; // 创建一个null的队列
Log.d("TAG", "-->> List Size = " + myList.size());
这个例子中,执行到Log打印队列长度时,大家都知道系统一定会报NullPointerException。然而如果在KT中,在调用myList的时候在它后面加上一个问号myList?.size()
,当myList为null的时候直接会打印List Size = null
并不会有null异常出现。
当使用Android Studio把上面那段Java自动转换成KT代码写法后:
val myList : ArrayList<String>? = null
Log.d("TAG", "-->> List Size = ${myList!!.size}")
编译器为什么自动把myList.size()
变成了myList!!.size
呢,为什么加上的是感叹号不是问号。
这是因为编译器在转化时为了保证代码转化前后的一致性所造成的。换句话说,在Java上出异常的,转化到KT上,编译器任然会让他保持抛出异常,NullPointerException也是如此。
所以结合上下文可以看得出,!!加上去后好像并没有和之前Java代码有什么区别嘛,该null的地方任然会抛出异常。所以大多数情况下都会使用?来检测null,轮不到!!出场。!!只会在你需要对某对象进行非空判断,并且需要抛出异常时才会使用到。
那我们接下来着重讲解一下?到底怎么用。
在声明对象时,把它跟在类名后面,表示这个类允许为null;
在调用对象时,把它跟在对象后面,表示如果为null程序就会视而不见。
如下列代码:
// 这是声明一个变量,问号跟在类名后面
var room: Room? = Room()
private fun checkRoom() {
// 因为加上了问号,所以可以任意的把room变成空
room = null
// 因为在调用时加上了问号,所以程序不会抛出异常
Log.d("TAG", "-->> room name = ${room?.roomName}")
}
再举个不用?的例子:
// 这样程序就默认的给room加上了!!,从此以后room不允许为null
var room: Room = Room()
private fun checkRoom() {
// 当把null赋给room时,从编译的时候就已经不通过
room = null
// 并且编译器建议把对象后面的问号删除,因为这个对象永远不为空
Log.d("TAG", "-->> room name = ${room.roomName}")
}
所以加上?是一种安全的写法,它体现了Kotlin null safety的特性。
KT的语法很灵动,定义参数还可以写成
val room: Room? = Room() // 先实例化一个room,并且room可以为空
val room: Room? = null // 不实例化了,开始room就是空的
val room: Room = Room() // 实例化一个room,并且room永远不能为空
val room = Room() // 和上一行代码一样,是KT最常用的简写语法
然而加上问号以后程序就万事大吉永远摆脱了NullPointerException的烦恼?我们再看下一段代码:
val roomList: ArrayList<Room>? = null
if (roomList?.size > 0) {
Log.d("TAG", "-->> 房间数不是0")
}
当我们判断list.size的时候,编译器会告诉我们"Operator call corresponds to a dot-qualified call 'roomList?.size.compareTo(0)' which is not allowed on a nullable receiver 'roomList?.size'."。大概意思是,当roomList为null的时,它的size返回就是"null",但是"null"不可以和int值比大小,所以编译器建议我们写成roomList?.size!! > 0
。
没错,经过编译器的建议加上了!!,我们程序运行到这行代码,roomList为null时它一定会报异常。所以是不是必须得在外面套一层if(roomList != null)
这种Java常见语句才能避免异常吗?
当然Kotlin不会让程序出现这种啰嗦的代码,所以里面提供了对象A ?: 对象B
表达式,并且取消了Java中的条件表达式 ? 表达式1 : 表达式2
这个三元表达式。
?:表示的意思是,当对象A值为null的时候,那么它就会返回后面的对象B。
val roomList: ArrayList<Room>? = null
val mySize= roomList?.size ?: 0
此时mySize的值就为0,因为roomList?.size为空。
所以我们可以把上面的代码改成这样:
val roomList: ArrayList<Room>? = null
if (roomList?.size ?: 0 > 0) { // 这一行添加了?:
Log.d("TAG", "-->> 房间数不是0")
}
就目前为止使,用上面的?和?:基本上能避免程序中出现的所有NullPointerException。
作者:Jason_Samuel
链接:https://www.jianshu.com/p/51b2e5aa3dd8
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
Kotlin中?和!!的区别的更多相关文章
- kotlin中“==”和“===”的区别
code 1 fun main(args: Array<String>) { val a : Int = 1000 println(a == a) //true println(a === ...
- Kotlin中的object 与companion object的区别
之前写了一篇Kotlin中常量和静态方法的文章,最近有人提出一个问题,在companion object中调用外部的成员变量会调用不到,这才意识到问题,本篇文章会带着这个疑问来解决问题. 一. obj ...
- Kotlin中与Java不同的地方 需要注意
1. 在Kotlin中不会将基本数据类型的自动转型比如 scriptIntrinsicBlur.setRadius(25) //报错, 必须写成 25f 或者 调用.toFloat() 2.Kotli ...
- Kotlin中常量和静态方法
常量 Java中: class StaticDemoActivity { public static final String LOAN_TYPE = "loanType"; pu ...
- 浅谈Kotlin中的函数
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/UV23Uw_969oVhiOdo4ZKAw作者:连凌能 Kotlin,已经被Android官方 ...
- kotlin中的嵌套类与内部类
Java中的内部类和静态内部类在Java中内部类简言之就是在一个类的内部定义的另一个类.当然在如果这个内部类被static修饰符修饰,那就是一个静态内部类.关于内部类 和静态内部类除了修饰符的区别之外 ...
- Kotlin中变量不同于Java: var 对val(KAD 02)
原文标题:Variables in Kotlin, differences with Java. var vs val (KAD 02) 作者:Antonio Leiva 时间:Nov 28, 201 ...
- MyBatis Mapper.xml文件中 $和#的区别
MyBatis Mapper.xml文件中 $和#的区别 网上有很多,总之,简略的写一下,作为备忘.例子中假设参数名为 paramName,类型为 VARCHAR . 1.优先使用#{paramN ...
- (实用篇)PHP中unset,array_splice删除数组中元素的区别
php中删除数组元素是非常的简单的,但有时删除数组需要对索引进行一些排序要求我们会使用到相关的函数,这里我们来介绍使用unset,array_splice删除数组中的元素区别吧 如果要在某个数组中删除 ...
随机推荐
- BZOJ 2226: [Spoj 5971] LCMSum 莫比乌斯反演 + 严重卡常
Code: #pragma GCC optimize(2) #include<bits/stdc++.h> #define setIO(s) freopen(s".in" ...
- select自定义箭头问题 。。。和一行内不同颜色的整体鼠标滑过变色
1.select自定义箭头问题 用<select><option></option></select>的时候自带的三角箭头与需要的三角不同,这是还要求有 ...
- WIN7自带端口转发渗透小技巧
目标是WIN7 X64,且开启了防火墙,想要用他的机器去访问别的机器,又不想登陆他的系统,常规办法一般是上传一个htran,然后进行转发,但是对方有杀软,有被杀的可能性,所以我用另外一种办法达到我的目 ...
- Centos7开机自动启动服务和联网
虚拟机设置选择NAT模式,默认情况下,Centos不是自动连接上网的,需要点击右上角,手动连接上网. 可以修改开机启动配置修改: 1. cd 到/etc/sysconfig/network-scrip ...
- Gym 100917M Matrix, The
题目链接: http://codeforces.com/gym/100917/problem/M --------------------------------------------------- ...
- statistics——数学统计函数
statistics——数学统计函数 转自:https://blog.csdn.net/zhtysw/article/details/80005410 资源代码位置:Lib/statistixs.py ...
- JS-格式化json
一 使用原生 JSON.stringify 实现 <textarea name="" id="myTA" cols="30" rows ...
- spring4.1.8扩展实战之六:注册bean到spring容器(BeanDefinitionRegistryPostProcessor接口)
本章是<spring4.1.8扩展实战>系列的第六篇,目标是学习如何通过自己写代码的方式,向spring容器中注册bean: 原文地址:https://blog.csdn.net/boli ...
- gcc -o hello hello.c 执行过程
GCC编译器驱动程序读取源程序文件hello.c,并将它翻译成一个可执行目标文件hello.这个翻译的过程可分为四个阶段. 1.预处理阶段 预处理器(cpp)根据以字符#开头的命令,修改原始的c程序. ...
- 16/7/14-MySQL-遇到的基本问题
从一开始遇到的3534 ---------------------------------------------------------------------------------------- ...