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);//隐藏虚拟按…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...