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删除数组中的元素区别吧 如果要在某个数组中删除 ...
随机推荐
- Task8.循环和递归神经网络
RNN提出的背景: RNN通过每层之间节点的连接结构来记忆之前的信息,并利用这些信息来影响后面节点的输出.RNN可充分挖掘序列数据中的时序信息以及语义信息,这种在处理时序数据时比全连接神经网络和CNN ...
- 英语单词independent
来源——https://www.docker.com/products/docker-hub 回到顶部 Share and Collaborate with Docker Hub Docker Hub ...
- python学习笔记(十八)python操作excel
python操作excel需要安装通过pip安装xlwt, xlrd这两个模块: pip install xlwt pip insall xlrd 操作excel ,写入excel: import x ...
- 帝国CMS编辑器粘贴Word图片
图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码 目前限chrome浏览器使用,但是项目要求需要支持所有的浏览器,包括Windows和macOS系统.没有办 ...
- [luogu]P1133 教主的花园[DP]
[luogu]P1133 教主的花园 ——!x^n+y^n=z^n 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会 ...
- CentOS 7.5 通过kubeadm部署k8s-1.15.0
kubeadm是Kubernetes官方提供的用于快速安装Kubernetes集群的工具,伴随Kubernetes每个版本的发布都会同步更新,kubeadm会对集群配置方面的一些实践做调整,通过实验k ...
- C#中如何通过点击按钮切换窗口
实现方法如下: 1.设计 首先在左侧放一个panel,右侧放一个panel(命名为pnlMain),调整大小,在左侧panel里放置两个按钮(多个按钮同理) 2.在按钮里面写方法 在[命名规范检查] ...
- UE4 命令行打开工程
创建快捷方式,目标填写: D:\EpicGames\4.14\Engine\Binaries\Win64\UE4Editor.exe "D:\YourProjectPath\YouProje ...
- python requests使用登陆之后的cookie
def getcontent(self): cookie_text=r'ur=FTW; mid=WsrlLwAEAAEfpCstNyTJl-1oZa0w; ig_pr=1; ig_vh=949; cs ...
- IBatis.Net 下使用SqlBulkCopy 大批量导入数据 问题解决
SQLBulkCopy是继承SQLClient空间下的一个特殊类,它可以帮助我们以映射的方式把DataTable和DataReader数据大批量导入到数据库对应表中 public void Inert ...