当前位置: 首页 > news >正文

Kotlin重点理解安全性

目录

  • 一 Kotlin安全性
    • 1.1 可空类型
    • 1.2 安全调用运算符
    • 1.3 Elvis 运算符
    • 1.4 非空断言运算符
    • 1.5 安全类型转换
    • 1.6 延迟初始化

一 Kotlin安全性

Kotlin 在设计时采用了一系列策略,旨在尽可能地减少空指针异常(NullPointerException)的出现。空指针异常是许多编程语言中常见的错误之一,Kotlin 通过以下几种方式来避免它:

  1. 可空类型(Nullable Types):Kotlin引入了可空类型的概念,允许变量具有可以存储空值的能力。在 Kotlin 中,如果一个变量可能为 null,必须显式地声明为可空类型。例如,使用 String? 表示一个可能为null的字符串类型。这样做可以在编译时就捕捉到潜在的空指针异常,因为 Kotlin 不允许直接对可空类型进行操作,除非先进行非空判断或者安全调用。
  2. 安全调用运算符(Safe Call Operator):在 Kotlin 中,可以使用 ?. 运算符来调用可空对象的方法或访问其属性。如果对象为 null,则整个表达式将返回 null 而不会导致空指针异常。例如,obj?.someMethod() 将返回 null,如果 obj 是 null,否则调用 someMethod() 方法。
  3. Elvis 运算符(Elvis Operator):Elvis 运算符 ?: 可以用于提供默认值,如果表达式的值为 null,则可以返回提供的默认值。例如,val length = str?.length ?: 0 表示如果 str 是 null,length 将赋值为 0。
  4. 非空断言运算符(Non-null Assertion Operator):有时候我们可以确定某个可空类型的变量在某个地方不会为 null,这时可以使用非空断言运算符 !! 来显式地告诉编译器该变量不会为 null。但是需要小心使用它,如果变量为 null,将会触发空指针异常。
  5. 安全类型转换(Safe Cast):使用 as? 运算符进行安全类型转换,如果转换失败,则返回 null。这样可以避免在类型转换时出现空指针异常。
  6. 延迟初始化:在 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 提供了多种方式来处理可空类型的变量:

  1. 安全调用操作符 ?.:允许在不确定变量是否为 null 的情况下,调用其方法或访问其属性。如果变量为 null,则整个表达式会返回 null。
val length = name?.length // 如果 name 不为 null,则返回 name 的长度,否则返回 null
  1. Elvis 操作符 ?::用于在表达式为 null 时提供默认值。
val nonNullName = name ?: "Unknown" // 如果 name 不为 null,则使用 name 的值,否则使用 "Unknown"
  1. 安全类型转换 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 在设计时采用了一系列策略&#xff0c;旨在尽可能地减少空指针异常&#xff08;NullPointerException&#xff09;的出现。空指…...

基于Java+SpringBoot+SpringCloud+Vue的智慧养老平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…...

Spring中的全局异常处理

在项目中通常会定义各种异常&#xff0c;比如断言异常、业务异常&#xff0c;甚至调用外部接口报的异常需要转成自己系统中的异常类型&#xff0c;这时就需要将各种异常类型进行统一的处理&#xff0c;返回统一的数据结构。在spring中提供了这样全局统一处理异常的注解Controll…...

【安全测试】Web应用安全之XSS跨站脚本攻击漏洞

目录 前言 XSS概念及分类 反射型XSS(非持久性XSS) 存储型XSS(持久型XSS) 如何测试XSS漏洞 方法一&#xff1a; 方法二&#xff1a; XSS漏洞修复 原则&#xff1a;不相信客户输入的数据 处理建议 资料获取方法 前言 以前都只是在各类文档中见到过XSS&#xff0c;也进…...

LeNet卷积神经网络-笔记

LeNet卷积神经网络-笔记 手写分析LeNet网三卷积运算和两池化加两全连接层计算分析 修正上图中H,W的计算公式为下面格式 基于paddle飞桨框架构建测试代码 #输出结果为&#xff1a; #[validation] accuracy/loss: 0.9530/0.1516 #这里准确率为95.3% #通过运行结果可以看出&am…...

使用XMLHttpRequest实现文件异步下载

1、问题描述 我想通过异步的方式实现下载文化&#xff0c;请求为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&#xff08;“Project Lombok”&#xff09;是一…...

springBean生命周期解析

本文基于Spring5.3.7 参考&#xff1a; kykangyuky Spring中bean的生命周期 阿斌Java之路 SpringBean的生命周期&#xff0c; 杨开振 JavaEE互联网轻量级框架整合开发 黑马程序员 JavaEE企业级应用开发教程 马士兵 Spring源码讲解 一. SpringBean生命周期流程图 二. 示例代码 …...

人工智能轨道交通行业周刊-第54期(2023.7.31-8.6)

本期关键词&#xff1a;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 是一个工具&#xff0c;旨在帮助定义和 共享多容器…...

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&#xff1a; Aggregate global unicast address&#xff0c;前3位是001&#xff0c;即2000::/3&#xff0c;目前IANA已经将一部分可聚合全球单播进行了专门使用&#xff0c;如&#xff1a;2001::/16用于IPV6互联网&#xff0c;…...

Nginx安装部署

什么是Nginx? Nginx&#xff08;发音同engine x&#xff09;是一款由俄罗斯程序员Igor Sysoev所开发轻量级的网页服务器、反向代 理服务器以及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。 Nginx 因具有高并发&#xff08;特別是静态资源&#xff09;、 占用系统资…...

物联网|按键实验---学习I/O的输入及中断的编程|读取I/O的输入信号|中断的编程方法|轮询实现按键捕获实验-学习笔记(13)

文章目录 实验目的了解擒键的工作原理及电原理图 STM32F407中如何读取I/O的输入信号STM32F407对中断的编程方法通过轮询实现按键捕获实验如何利用已有内工程创建新工程通过轮询实现按键捕获代码实现及分析1 代码的流程分析2 代码的实现 Tips:下载错误的解决 实验目的 了解擒键…...

Hadoop-HDFS的Namenode及Datanode(参考Hadoop官网)

HDFS有什么特点&#xff0c;被设计做什么 Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。有一下几个特点&#xff1a; HDFS是一个高度容错性的系统&#xff0c;具有高容错、高可靠性、高扩展性的特点&#xff0c;适合部…...

C:通过alarm发送信号

可以通过alarm定时发送SIGALRM信号&#xff1a; #include <unistd.h> unsigned int alarm(unsigned int seconds); alarm()函数用来在seconds秒之后安排发送一个SIGALRM信号&#xff0c;如果seconds为0&#xff0c;将取消所有已设置的闹钟请求。alarm()函数的返回值是以前…...

如何将 dubbo filter 拦截器原理运用到日志拦截器中?

业务背景 我们希望可以在使用日志拦截器时&#xff0c;定义属于自己的拦截器方法。 实现的方式有很多种&#xff0c;我们分别来看一下。 拓展阅读 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)指针数组的实质是一个数组&#xff0c;这个数组中存…...

【uniapp APP隐藏顶部的电量,无线,时间状态栏与导航栏】

uniapp APP隐藏顶部的电量&#xff0c;无线&#xff0c;时间状态栏 如下代码配置&#xff08;在一个页面设置这个段代码&#xff0c;所有页面都会消失&#xff09; onShow() {// #ifdef APP-PLUS// 隐藏顶部电池,时间等信息 plus.navigator.setFullscreen(true);//隐藏虚拟按…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...