Kotlin重点理解安全性
目录
- 一 Kotlin安全性
- 1.1 可空类型
- 1.2 安全调用运算符
- 1.3 Elvis 运算符
- 1.4 非空断言运算符
- 1.5 安全类型转换
- 1.6 延迟初始化
一 Kotlin安全性
Kotlin 在设计时采用了一系列策略,旨在尽可能地减少空指针异常(NullPointerException)的出现。空指针异常是许多编程语言中常见的错误之一,Kotlin 通过以下几种方式来避免它:
- 可空类型(Nullable Types):Kotlin引入了可空类型的概念,允许变量具有可以存储空值的能力。在 Kotlin 中,如果一个变量可能为 null,必须显式地声明为可空类型。例如,使用 String? 表示一个可能为null的字符串类型。这样做可以在编译时就捕捉到潜在的空指针异常,因为 Kotlin 不允许直接对可空类型进行操作,除非先进行非空判断或者安全调用。
- 安全调用运算符(Safe Call Operator):在 Kotlin 中,可以使用 ?. 运算符来调用可空对象的方法或访问其属性。如果对象为 null,则整个表达式将返回 null 而不会导致空指针异常。例如,obj?.someMethod() 将返回 null,如果 obj 是 null,否则调用 someMethod() 方法。
- Elvis 运算符(Elvis Operator):Elvis 运算符 ?: 可以用于提供默认值,如果表达式的值为 null,则可以返回提供的默认值。例如,val length = str?.length ?: 0 表示如果 str 是 null,length 将赋值为 0。
- 非空断言运算符(Non-null Assertion Operator):有时候我们可以确定某个可空类型的变量在某个地方不会为 null,这时可以使用非空断言运算符 !! 来显式地告诉编译器该变量不会为 null。但是需要小心使用它,如果变量为 null,将会触发空指针异常。
- 安全类型转换(Safe Cast):使用 as? 运算符进行安全类型转换,如果转换失败,则返回 null。这样可以避免在类型转换时出现空指针异常。
- 延迟初始化:在 Kotlin 中,类的属性可以使用 lateinit 延迟初始化,这使得在声明属性时不需要立即初始化,而可以在稍后进行初始化。但是要小心使用延迟初始化,必须确保在使用该属性之前已经初始化,否则会抛出异常。
1.1 可空类型
在 Kotlin 中,可空类型(Nullable Types)允许变量具有可以存储 null 值的能力。通常,变量的类型不能为 null,如果试图将 null 赋值给非空类型的变量,编译器会报错。但是,有时候我们需要表示一个变量可能为 null 的情况,这就是可空类型的用途。
在 Kotlin 中,声明可空类型的变量时,在类型名称后面添加一个问号 ? 来表示该变量可以为 null。例如,String? 表示一个可能为 null 的字符串类型,Int? 表示一个可能为 null 的整数类型。
以下是一些可空类型的示例:
fun main() {var name: String? = "John" // 可以为 null 的字符串var age: Int? = null // 可以为 null 的整数val nullableList: List<Int>? = listOf(1, 2, 3) // 可以为 null 的整数列表// 当然,我们也可以使用非空类型的列表val nonNullableList: List<Int> = listOf(1, 2, 3)
}
在使用可空类型时,需要特别注意处理可能为 null 的情况,以避免空指针异常。Kotlin 提供了多种方式来处理可空类型的变量:
- 安全调用操作符 ?.:允许在不确定变量是否为 null 的情况下,调用其方法或访问其属性。如果变量为 null,则整个表达式会返回 null。
val length = name?.length // 如果 name 不为 null,则返回 name 的长度,否则返回 null
- Elvis 操作符 ?::用于在表达式为 null 时提供默认值。
val nonNullName = name ?: "Unknown" // 如果 name 不为 null,则使用 name 的值,否则使用 "Unknown"
- 安全类型转换 as?:用于安全地进行类型转换,如果转换失败,则返回 null。
val intValue: Int? = stringValue as? Int // 如果 stringValue 可以转换为 Int,则返回 Int 值,否则返回 null
通过使用可空类型和相应的操作符,我们可以在编译时处理潜在的 null 值,避免空指针异常,并使得代码更加健壮和安全。
val str: String? = null
val length = str.length // 编译错误:str 可能为 null
let 函数可以用于在非空的情况下执行某些操作,例如:
val str: String? = null
str?.let {// str 不为 null 时执行println(it.length)
}
optional 函数可以用于在可空类型的变量为 null 时执行某些操作,例如:
val str: String? = null
str.optional {// str 为 null 时执行println("str is null")
}
1.2 安全调用运算符
在 Kotlin 中,安全调用运算符(Safe Call Operator)是一种用于处理可空类型的特殊运算符。它允许你在不确定一个可空类型变量是否为 null 的情况下,安全地调用它的方法或访问它的属性。如果变量为 null,那么整个表达式会返回 null,而不会导致空指针异常。
安全调用运算符的语法是 ?.,它用于在可空类型变量后面调用其方法或访问其属性。以下是使用安全调用运算符的示例:
fun printLength(name: String?) {val length = name?.lengthprintln("Length of name: $length")
}fun main() {printLength("John") // 输出: Length of name: 4printLength(null) // 输出: Length of name: null
}
在上面的示例中,我们定义了一个名为 printLength 的函数,它接受一个可空类型的字符串 name 作为参数。在函数中,我们使用安全调用运算符 name?.length 来获取 name 字符串的长度,如果 name 是 null,则整个表达式会返回 null,否则返回字符串的长度。这样,在处理可空类型时,就不需要手动进行 null 检查,可以避免空指针异常。
安全调用运算符在处理链式调用时尤为有用。例如,如果我们有一个可空类型的对象 person,它有一个可空类型的属性 address,并且 address 有一个可空类型的属性 city,我们可以通过链式使用安全调用运算符来避免多层嵌套的 null 检查:
val city = person?.address?.city
上面的代码会在 person、address 或 city 中任何一个为 null 时返回 null,而不会抛出空指针异常。
通过使用安全调用运算符,我们可以更加简洁和安全地处理可空类型的变量,减少了大量的 null 检查代码,提高了代码的可读性和健壮性。
1.3 Elvis 运算符
在 Kotlin 中,Elvis 运算符 ?: 是一种用于处理可空类型的特殊运算符。它提供了一种简洁的方式来为可能为 null 的表达式提供一个默认值。如果表达式的值为 null,那么 Elvis 运算符会返回指定的默认值,否则返回表达式的值。
Elvis 运算符的语法是 expression ?: defaultValue,其中 expression 是一个可能为 null 的表达式,defaultValue 是一个默认值,用于在 expression 为 null 时返回。
以下是使用 Elvis 运算符的示例:
fun printLength(name: String?) {val length = name?.length ?: -1println("Length of name: $length")
}fun main() {printLength("John") // 输出: Length of name: 4printLength(null) // 输出: Length of name: -1
}
在上面的示例中,我们定义了一个名为 printLength 的函数,它接受一个可空类型的字符串 name 作为参数。在函数中,我们使用 Elvis 运算符 name?.length ?: -1 来获取 name 字符串的长度,如果 name 是 null,则整个表达式会返回 -1,否则返回字符串的长度。这样,我们可以指定一个默认值 -1,以避免 name 为 null 时导致的空指针异常。
Elvis 运算符还可以用于链式调用中的多个可空类型变量:
val city = person?.address?.city ?: "Unknown"
在上面的代码中,如果 person、address 或 city 中任何一个为 null,都会返回 “Unknown” 作为默认值。
通过使用 Elvis 运算符,我们可以更加简洁地处理可空类型的变量,并在需要时为其提供默认值,使得代码更加健壮和安全。
1.4 非空断言运算符
在 Kotlin 中,非空断言运算符 !! 是一种用于处理可空类型的特殊运算符。它用于显式地告诉编译器一个可空类型的变量不会为 null,从而允许在变量为 null 的情况下进行非空操作。
非空断言运算符的语法是 expression!!,其中 expression 是一个可空类型的变量。如果 expression 不为 null,那么 expression!! 会返回它的值;但如果 expression 为 null,那么在运行时会抛出 NullPointerException。
需要注意的是,非空断言运算符 !! 是一种危险的操作。如果使用不当,会导致空指针异常,因此应该谨慎使用。通常情况下,最好避免使用 !!,而是使用安全调用运算符 ?. 或 Elvis 运算符 ?: 来处理可空类型的变量。
以下是使用非空断言运算符的示例:
fun printLength(name: String?) {val length = name!!.lengthprintln("Length of name: $length")
}fun main() {printLength("John") // 输出: Length of name: 4printLength(null) // 抛出 NullPointerException
}
在上面的示例中,我们定义了一个名为 printLength 的函数,它接受一个可空类型的字符串 name 作为参数。在函数中,我们使用非空断言运算符 name!!.length 来获取 name 字符串的长度。如果 name 是 null,则在运行时会抛出 NullPointerException。
尽管非空断言运算符 !! 可以在某些情况下方便地处理可空类型的变量,但它应该谨慎使用,并且只在你能确保变量不会为 null 的情况下使用。通常情况下,推荐使用更安全的操作符来处理可空类型,以避免潜在的空指针异常。
1.5 安全类型转换
在 Kotlin 中,安全类型转换(Safe Cast)是一种用于处理类型转换的特殊操作符。它允许你安全地将一个对象转换为指定类型,如果转换失败,则返回 null,而不会抛出 ClassCastException 异常。
安全类型转换的语法是 as?,它用于将一个对象转换为指定类型,并返回转换后的对象。如果转换失败,则整个表达式会返回 null。
以下是使用安全类型转换的示例:
fun printLength(name: Any) {val length = (name as? String)?.lengthprintln("Length of name: $length")
}fun main() {printLength("John") // 输出: Length of name: 4printLength(42) // 输出: Length of name: null
}
在上面的示例中,我们定义了一个名为 printLength 的函数,它接受一个 Any 类型的参数 name。在函数中,我们首先使用 as? 运算符将 name 对象安全地转换为 String 类型。如果 name 是 String 类型,则转换成功,我们可以获取它的长度并打印;如果 name 不是 String 类型,则转换失败,整个表达式会返回 null。
在 main 函数中,我们分别调用了 printLength(“John”) 和 printLength(42)。第一个调用中,name 是一个字符串,转换成功,打印字符串的长度。第二个调用中,name 是一个整数,转换失败,返回 null。
安全类型转换可以帮助我们处理不确定对象类型的情况,而不会出现 ClassCastException 异常。它是一种安全而方便的方式来进行类型转换,特别在处理多态类型的对象时很有用。
1.6 延迟初始化
在 Kotlin 中,延迟初始化(Late Initialization)是一种允许在声明属性时不立即初始化的特性。在某些情况下,我们希望在稍后的时间点才对属性进行初始化,例如在构造函数执行之后或在对象创建之后。
为了实现延迟初始化,我们需要在属性声明中使用 lateinit 关键字,并将属性的类型设置为非空类型(不可为 null)。这样,编译器会知道该属性会在稍后被初始化,而不会在初始化阶段要求立即赋值。
以下是一个简单的示例,演示了如何在 Kotlin 中使用延迟初始化:
class Person {lateinit var name: Stringlateinit var age: Intfun init(name: String, age: Int) {this.name = namethis.age = age}
}fun main() {val person = Person()person.init("Alice", 30)println("Name: ${person.name}")println("Age: ${person.age}")
}
在上面的示例中,我们定义了一个 Person 类,其中的 name 和 age 属性使用了延迟初始化。我们在类的 init 方法中进行属性的初始化。因为属性使用了 lateinit 关键字,所以在创建 Person 对象时,并不需要立即为 name 和 age 赋值。相反,我们可以在稍后的时间点通过调用 init 方法来为它们赋值。
需要注意的是,使用 lateinit 的属性必须是非空类型,并且必须在对象的生命周期内进行初始化,否则会抛出 UninitializedPropertyAccessException 异常。因此,使用延迟初始化时要确保在使用属性之前已经进行了初始化。
延迟初始化非常有用,可以在某些情况下优化对象的创建和初始化过程,避免不必要的资源消耗,并提高代码的性能。但是要小心使用它,确保在适当的时间点对属性进行初始化。
相关文章:
Kotlin重点理解安全性
目录 一 Kotlin安全性1.1 可空类型1.2 安全调用运算符1.3 Elvis 运算符1.4 非空断言运算符1.5 安全类型转换1.6 延迟初始化 一 Kotlin安全性 Kotlin 在设计时采用了一系列策略,旨在尽可能地减少空指针异常(NullPointerException)的出现。空指…...
基于Java+SpringBoot+SpringCloud+Vue的智慧养老平台设计与实现(源码+LW+部署文档等)
博主介绍: 大家好,我是一名在Java圈混迹十余年的程序员,精通Java编程语言,同时也熟练掌握微信小程序、Python和Android等技术,能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…...
Spring中的全局异常处理
在项目中通常会定义各种异常,比如断言异常、业务异常,甚至调用外部接口报的异常需要转成自己系统中的异常类型,这时就需要将各种异常类型进行统一的处理,返回统一的数据结构。在spring中提供了这样全局统一处理异常的注解Controll…...
【安全测试】Web应用安全之XSS跨站脚本攻击漏洞
目录 前言 XSS概念及分类 反射型XSS(非持久性XSS) 存储型XSS(持久型XSS) 如何测试XSS漏洞 方法一: 方法二: XSS漏洞修复 原则:不相信客户输入的数据 处理建议 资料获取方法 前言 以前都只是在各类文档中见到过XSS,也进…...
LeNet卷积神经网络-笔记
LeNet卷积神经网络-笔记 手写分析LeNet网三卷积运算和两池化加两全连接层计算分析 修正上图中H,W的计算公式为下面格式 基于paddle飞桨框架构建测试代码 #输出结果为: #[validation] accuracy/loss: 0.9530/0.1516 #这里准确率为95.3% #通过运行结果可以看出&am…...
使用XMLHttpRequest实现文件异步下载
1、问题描述 我想通过异步的方式实现下载文化,请求为post请求。一开始我打算用ajax。 $.ajax({type:post,contentType:application/json,url:http://xxx/downloadExcel,data:{data:JSON.stringify(<%oJsonResponse.JSONoutput()%>)},}).success(function(dat…...
Lombok 的安装与使用
文章目录 一、什么是 Lombok1.1 Lombok 的概念1.2 为什么使用 Lombok1.3 Lombok 的相关注解 二、Lombok 的安装2.1 引入依赖2.2 安装插件 三、Lombok 的使用案例四、Lombok 的原理 一、什么是 Lombok 1.1 Lombok 的概念 Lombok(“Project Lombok”)是一…...
springBean生命周期解析
本文基于Spring5.3.7 参考: kykangyuky Spring中bean的生命周期 阿斌Java之路 SpringBean的生命周期, 杨开振 JavaEE互联网轻量级框架整合开发 黑马程序员 JavaEE企业级应用开发教程 马士兵 Spring源码讲解 一. SpringBean生命周期流程图 二. 示例代码 …...
人工智能轨道交通行业周刊-第54期(2023.7.31-8.6)
本期关键词:BIM智能运维、铁水联运、编组站美容、鸿蒙4.0、LK-99完全悬浮 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道世界…...
Docker Compose 使用方法
目录 前言 安装 Docker Compose Ubuntu 安装与更新 Red Hat 安装与更新 验证是否安装 Docker Compose 创建 docker-compose.yml 文件 创建一个MySQL 与 tomcat 示例 使用Docker Compose启动服务 前言 Docker Compose 是一个工具,旨在帮助定义和 共享多容器…...
HTML 初
前言 HTML的基本骨架 HTML基本骨架是构建网页的最基本的结果。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…...
IPv6地址分类,EUI-64转换规则
1、可聚合的单全球单播地址Global Unique Address: Aggregate global unicast address,前3位是001,即2000::/3,目前IANA已经将一部分可聚合全球单播进行了专门使用,如:2001::/16用于IPV6互联网,…...
Nginx安装部署
什么是Nginx? Nginx(发音同engine x)是一款由俄罗斯程序员Igor Sysoev所开发轻量级的网页服务器、反向代 理服务器以及电子邮件(IMAP/POP3)代理服务器。 Nginx 因具有高并发(特別是静态资源)、 占用系统资…...
物联网|按键实验---学习I/O的输入及中断的编程|读取I/O的输入信号|中断的编程方法|轮询实现按键捕获实验-学习笔记(13)
文章目录 实验目的了解擒键的工作原理及电原理图 STM32F407中如何读取I/O的输入信号STM32F407对中断的编程方法通过轮询实现按键捕获实验如何利用已有内工程创建新工程通过轮询实现按键捕获代码实现及分析1 代码的流程分析2 代码的实现 Tips:下载错误的解决 实验目的 了解擒键…...
Hadoop-HDFS的Namenode及Datanode(参考Hadoop官网)
HDFS有什么特点,被设计做什么 Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。有一下几个特点: HDFS是一个高度容错性的系统,具有高容错、高可靠性、高扩展性的特点,适合部…...
C:通过alarm发送信号
可以通过alarm定时发送SIGALRM信号: #include <unistd.h> unsigned int alarm(unsigned int seconds); alarm()函数用来在seconds秒之后安排发送一个SIGALRM信号,如果seconds为0,将取消所有已设置的闹钟请求。alarm()函数的返回值是以前…...
如何将 dubbo filter 拦截器原理运用到日志拦截器中?
业务背景 我们希望可以在使用日志拦截器时,定义属于自己的拦截器方法。 实现的方式有很多种,我们分别来看一下。 拓展阅读 java 注解结合 spring aop 实现自动输出日志 java 注解结合 spring aop 实现日志traceId唯一标识 java 注解结合 spring ao…...
【java】【maven】【基础】MAVEN安装配置介绍
目录 1 下载 2 安装-windows为例 3 配置环境变量 3.1 JAVA_HOME 3.2 MAVEN_HOME 3.3 PATH 3.4 验证 4 MAVEN基础概念 4.1 仓库概念 4.2 坐标概念 4.2.1 打开网址 4.2.2 输入搜索内容junit 4.2.3 找到对应API名称点击 4.2.4 点击对应版本 4.2.5 复制MAVEN坐标 4.3 配置…...
【C语言进阶】指针的高级应用(下)
文章目录 一、指针数组与数组指针1.1 指针数组与数组指针的表达式 二、函数指针2.1 函数指针的书写方式 三、二重指针与一重指针3.1 二重指针的本质3.2 二重指针的用法3.3 二重指针与数组指针 总结 一、指针数组与数组指针 (1)指针数组的实质是一个数组,这个数组中存…...
【uniapp APP隐藏顶部的电量,无线,时间状态栏与导航栏】
uniapp APP隐藏顶部的电量,无线,时间状态栏 如下代码配置(在一个页面设置这个段代码,所有页面都会消失) onShow() {// #ifdef APP-PLUS// 隐藏顶部电池,时间等信息 plus.navigator.setFullscreen(true);//隐藏虚拟按…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
