Kotlin语法学习(四)_空指针检查

news2024/11/27 18:27:55

空指针检查

  • 空指针异常是一种不受编程语言检查的运行时异常,只能由程序员主动通过逻辑判断来避免,所以空指针异常往往比较容易出这个问题

可空类型系统

  • 在Kotlin当中利用了编译时判空检查的机制几乎杜绝了空指针异常,Kotlin提供了一些列的工具,让我们能够轻松处理各种判空情况
fun doStudy(study: Study) {
    study.readBooks()
    study.doHomeWork()
}
  • 上面这个代码如果使用Java语言来进行编写的话,当我们参数传递为null,那么下面调用两个方法就会爆出空指针异常,所以在调用方法之前应该检查一下参数是否为空,这样的话就不会出现空指针异常
fun doStudy(study: Study) {
    if(study != null) {
        study.readBooks()
        study.doHomeWork()
    }
}
  • 但是实际上,在Kotlin当中,根本不用if来进行判断study参数是否为空,因为在Kotlin语法中,默认所有的参数和变量都是不可以为空的,所以这里传入的Study参数一定不会为空,我们可以放心的调用它的任何函数.
  • 但是如果尝试向doStudy函数中传递一个空的Study参数,编译器就会提示一个如下的错误出现,也就是说,Kotlin将空指针的检查提前到了编译阶.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3qqhGR9Z-1669110110989)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221122160531510.png)]

  • 但是这个的前提是,Kotlin当中的所有的参数和变量都默认不为空,但是当我们的业务逻辑要求某个参数就是为空该怎么办呢?
  • 不用担心在Kotlin当中为我们提供了另外一套可以为空的系统,只不过就是在使用可以为空的系统的时候,我们需要在编译阶段就将所有潜在空指针异常的地方处理掉,否者代码无法编译通过
  • 所谓可以为空的系统激素hi在类名的后面加上一个?号,比如Int表示不可以为空的整形,Int?表示一个可以为空的整形
  • 回到刚刚的doStudy()函数,如果我们希望传入的参数的可以为空,那么就将Study改成Study?
fun main() {
    doStudy(null)
}
fun doStudy(study: Study?) {
    study.readBooks()
    study.doHomeWork()
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5skrv8Pv-1669110110991)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221122161312716.png)]

  • 可以看到调用doStudy()函数传入null的时候,不会再提示上面的错误了,意思就是现在Study这个参数可以为空了,但是发现在下面调用study参数的两个方法的时候,发生了报错
  • 由于我们将参数改成了可空的Study?类型,此时调用readBooks()和doHomeWork()方法的时候都有可能会造成空指针,因此在这种情况下Kotlin不允许编译通过
  • 改进代码就是
fun doStudy(study: Study?) {
    if (study != null) {
        study.readBooks()
        study.doHomeWork()
    }
}
  • 为了能够在编译时期就处理掉所有的空指针异常,通常需要编写很多的额外代码才行,如果每处都是用if来进行判断,就会比较啰嗦,而且if语句还是处理不了全局变量的判空问题
  • 为此Koltin提供了一系列的辅助工具,使开发者能够更轻松地进行空指针处理.

判空辅助工具

  • 首先是最常用的?.操作符,这个操作符的作用是,当对象不为空时正常调用,当对象为空的时候什么也不干.
  • 了解了?.操作符之后,doStudy()函数进行优化,代码如下
fun doStudy(study: Study?) {
    study?.doHomeWork()
    study?.readBooks()
}
  • 还有一个非常常用的?:操作符,这个操作符的左右两边都接受一个表达式,当左边表达式不为空的时候,就输出左边表达式的值,否者就输出右边表达式的值
  • 编写一段函数来输出一段文本的长度
fun getTextLength(text: String?) = text?.length ?: 0
  • Kotlin的空指针检查机制也不是总是那么智能,有时候我们从逻辑上将空指针异常处理了,但是Kotlin的编译器并不知道,这个时候他还是会编译失败
val content: String? = "hello"

fun main() {
    if(content != null) {
        printUpperCase()
    }
}
fun printUpperCase() {
    val upperCase= content.toUpperCase()
    println(upperCase)
}
  • 在上述的代码中定义了一个全局变量content,在main函数当中我们在调用printUpperCase()函数之前就已经判断了content是否为空,所以在printUpperCase()函数中content不可能为空
  • 但是很遗憾的是,这段代码一定是无法运行的,因为printUpperCase()函数并不知道外部已经对content变量进行非空检查,在调用toUpperCase()函数的时候,不知道外部已经将content变量进行了非空检查,所以content在调用toUpperCase()函数的时候还是会存在空指针异常.
  • 在这种情况下,如果我们想要强行的通过编译,可以使用非空断言工具,写法是在对象的后面加上!!操作符
fun printUpperCase() {
    val upperCase = content!!.toUpperCase()
    println(upperCase)
}
  • 这是一种有风险的写法,意在告诉Kotlin,我非常确信这里的对象不会为空,所以你就不用来帮我做空指针的检查了,如果出现空指针问题,你抛出空指针异常,后果由我来进行承担
  • 所以这种写法是存在潜在的空指针问题的,如果有更好的写法不建议这样使用
  • let工具.let既不是操作符,也不是关键字.而是一个函数.这个函数提供了函数式API接口,并将原始调用对象作为参数传递到Lambda表达式当中
obj.let { obj2 ->
    //编写具体的业务逻辑
}
  • let结合?.操作符将doStudy()方法进行优化
fun doStudy(study: Study?) {
    study?.let {stu ->
          stu.readBooks()
          stu.doHomeWork()      
    }
}
  • ?.操作符表示对象对空的时候什么都不做,对象不为空的时候就调用let函数,而let函数会将study对象本身作为参数传递刀Lambda表达式当中,此时study对象肯定就不为空了,我们就可以放心的任意调用他的方法了
  • Lambda表达式有一个特性就是说,当Lambda表达式的参数裂掉只有一个参数的时候,可以不声明参数的名字,直接使用it关键字来进行代替即可
fun doStudy(study: Study?) {
    study?.let {
        it.readBooks()
        it.doHomeWork()
    }
}
  • let函数可以处理全局变量的判空问题,而if语句无法做到这一点,比如我们将doStudy()函数中的参数变成一个全局变量,使用let函数仍然可以正常工作,但是使用if判断语句会提示报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CmyVFq1R-1669110110992)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%89%E5%8D%93/image-20221122173559106.png)]

  • 之所以在这个地方会报错是因为全局变量的值,随时有可能会被其他线程所修改,即使做了判空处理,任然无法保证study变量没有空指针风险,这一点也体现出了let函数的优势.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/27043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Verilog 随机数及概率分布

随机数 Verilog 中使用系统任务 $random(seed) 产生随机数,seed 为随机数种子。seed 值不同,产生的随机数也不同。如果 seed 相同,产生的随机数也是一样的。可以为 seed 赋初值,也可以忽略 seed 选项,seed 默认初始值为…

130. 被围绕的区域

130. 被围绕的区域 给你一个 m∗nm * nm∗n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。 实例1: 输入:board [[“X”,“X”,“X”,“X”],…

内容云筑底,火山引擎能否为企业添一把火?

在App里面再搭一个“今日头条”,让用户在自家的App里看图文、刷视频,这是很多企业都想干的一件事情。尤其是对于用户使用频率低的App而言,他们更需要依靠信息流内容加长用户停留时间,增加用户互动次数,进而留住用户&am…

神经网络和深度学习-梯度下降Gradient Descent

梯度下降 损失函数 绝大多数的机器学习模型都会有一个损失函数。比如常见的均方误差(Mean Squared Error)损失函数: L(w,b)1N∑i1N(yi−f(wxib))2L(w, b)\frac{1}{N} \sum_{i1}^{N}\left(y_{i}-f\left(w x_{i}b\right)\right)^{2} L(w,b)N1​i1∑N​(y…

物理层物理层

该层解决具体比特传输问题 一般的数据通信系统如图: 该系统可按通信方式分为两种:同步/异步通信和模拟/数字通信: 异步通信是通信双方各自时钟独立,每次只传输一个字符,时钟在传送开始时对齐;这种机制简单…

[附源码]计算机毕业设计JAVA驾校管理系统

[附源码]计算机毕业设计JAVA驾校管理系统 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis M…

Docker(四):Docker可视化管理工具

背景 在技术这一行,学无止境,无数的知识点在大脑里面堆积着。各种命令行脚本(Python,Java,Nodejs,Linux,Docker)数不胜数,如果有视图化的管理工具,帮我们管理着这些命令行脚本,岂不美哉。可以节…

11.22Spring 学习day02

1. 1.1 XML和注解的区别 xml优点: 把标签配置和java代码解耦一目了然,对于业务量大的需求,可以清晰表明各个对象的关系 缺点: 配置不方便,读取和解析需要一定的时间无法及时校验正确性 注解优点: 配置…

返乡人员信息登记管理系统,助力精准管控

随着全国疫情的零星化,再加上元旦与春节很快就要来临了。这几个月各省的人员流动性肯定会逐渐增加,为了应对佳节的人流高峰期,不少省市都早已发出通知。要求返乡人员提前3天提前报备行程,从而便于极大地提高了登记效率&#xff0c…

数字集成电路设计(五、仿真验证与 Testbench 编写)(四)

文章目录7. 用户自定义元件模型7.1 UDP应用实例8. 基本门级元件和模块的延时建模8.1 门级延迟建模8.1.1 门级延迟的基本延迟表达形式8.1.2 门级延迟的最小、典型、最大延迟表达形式8.1.3 例子用VerilogHDL建立图5.8-1 模块D的延迟仿真模块8.2 模块延迟建模8.2.1 延迟说明块 Spe…

数据分析和可视化必备的几大软件,你用过几个?

本文主要是面向数据分析初学者,因此分享的基本是一些免编程的可视化工具,详细介绍了7款工具,推荐大家使用,主要是让初学数据分析的朋友知道可视化工具大概有哪些、流行的有哪些。 Power BI Power BI是微软开发的商业分析工具。用户…

LeetCode 91 双周赛

2465. 不同的平均值数目 给你一个下标从 0 开始长度为 偶数 的整数数组 nums 。 只要 nums 不是 空数组,你就重复执行以下步骤: 找到 nums 中的最小值,并删除它。找到 nums 中的最大值,并删除它。计算删除两数的平均值。 两数…

mysql InnooDb存储引擎的体系结构和逻辑存储结构

前言 这是一篇理论性比较强的文章,是不是很多人一听理论性的东西,就被劝退了?可千万别。其实分享内容非常简单,也非常干,相信你会喜欢的,对你也是有帮助的。切入正题,mysql的体系结构可以作为一…

机理类模型的建模思路|2021年亚太赛B题|2022备赛|前景目标提取

目录 一、 前景目标提取问题 1.背景目标和前景目标提取 2.问题一 2.2问题一求解 3.问题二 4.问题三 5.问题四 6.问题五​ 7.问题六 8.矩阵范数 二、前景目标提取——机理总结 三、编程实现 一、 前景目标提取问题 1.背景目标和前景目标提取 不动 & 动 视…

redis集群

Redis集群在保证主从加哨兵的基本功能之外,还能够提升Redis存储数据的能力。 一致性hash环 k1-->crc(16)? 0-16384 redis集群的ping-pang机制:一个主机向另一个主机ping,另一个pang回来,说明连接成功,通过这样的方…

脑与认知科学基础(期末复习)

脑与认知科学基础(期末复习) 文章目录脑与认知科学基础(期末复习)第一章 脑与认知科学简介认知元认知中国脑计划第二章 大脑简介Human brain解剖参考坐标大脑皮质脑的内侧和腹侧面神经系统神经系统的细胞神经元间信号传导神经回路…

【LeetCode】No.94. Binary Tree Inorder Traversal -- Java Version

题目链接:https://leetcode.com/problems/binary-tree-inorder-traversal/ 1. 题目介绍(Binary Tree Inorder Traversal) Given the root of a binary tree, return the inorder traversal of its nodes’ values. 【Translate】&#xff1a…

Trie字典树详解

字典树📖1. 什么是Trie树📖2. Trie树的一些应用场景📖3. Trie树的优缺点📖4. Trie树的节点怎样定义📖5. 代码实现📖6. 字典树的优化📖1. 什么是Trie树 Trie树,又叫字典树&#xff0…

linux性能中常用压测工具

stress工具 stress是Linux的一个压力测试工具,可以对CPU、Memory、IO、磁盘进行压力测试。 安装: sudo yum install stress 命令的使用: -c, --cpu N:产生N个进程,每个进程都循环调用sqrt函数产生CPU压力。 -i, --io N:产生N个进…

Java搭建实战springboot基于若依项目工时统计成本核算管理源码

大家好啊,我是测评君,欢迎来到web测评。 本期给大家带来一套基于若依开发的springboot项目工时统计成本核算管理源码,该系统是前后端分离的架构,前端使用Vue2,后端使用SpringBoot2。 技术架构 技术框架:Sp…