当前位置:   article > 正文

【Kotlin】空安全总结 ( 变量可空性 - 手动空安全管理 - 空安全调用操作符 - 非空断言操作符 - 空合并操作符 - 空指针异常处理 - 先决条件函数判空 )_kotlin 多变量 非空判断

kotlin 多变量 非空判断

![在这里插入图片描述](https://img-
blog.csdnimg.cn/b348d6f3f301482c8e6845676674b346.gif#pic_center)

文章目录
  • 一、Kotlin 的空安全机制
  • 二、变量可空性
  • * 1、默认变量不可赋空值
    
    • 1
    • 2、声明可空类型变量
  • 三、手动空安全管理
  • 四、空安全调用操作符 ?
  • 五、let 函数结合空安全调用操作符使用
  • 六、非空断言操作符 !!
  • 七、使用 if 语句判空
  • 八、空合并操作符 ?:
  • 九、空合并操作符与 let 函数结合使用
  • 十、空指针异常处理
  • * 1、捕获并处理异常
    
    • 1
    • 2、抛出自定义异常
  • 十一、先决条件函数判空
  • * 1、先决条件函数概念
    
    • 1
    • 2、先决条件函数原型
    • 3、先决条件函数代码示例

一、Kotlin 的空安全机制


Java 中的空指针问题 :

Java 语言 编写的程序中 , 出现最多的崩溃就是 NullPointerException 空指针异常 ,

该异常是 运行时 才爆出的 , 在 代码编写时 以及 编译期 很难提前排查出来 ;

Kotlin 的空安全机制 :

在 Kotlin 语言 中 , 针对 空指针异常 问题 进行了优化 , 引入了 空安全机制 ,

在代码编写后的 编译期 , 就可以 提前排查出可能出现的空指针异常问题 , 并提前进行处理 ,

这样极大地提高了 Kotlin 程序的 代码健壮性 ;

二、变量可空性


1、默认变量不可赋空值

在 Java 中 , 引用类型的变量 默认为 null 空值 ;

但是在 Kotlin 中 , 变量默认不可为 null 空值 ,

这样所有的 变量 在默认状态下 , 都有一个 默认的实例对象 ,

从而极大的 减少了 空指针异常 出现的概率 ;

代码示例 : 先定义一个 name 变量 , 为其赋值字符串 "Tom" ,

然后再为其赋值 null 空值 ;


fun main() {
var name = “Tom”
name = null
}

此时 , 在 IntelliJ IDEA 中 就会提示如下报错信息 :


Null can not be a value of a non-null type String

在这里插入图片描述
这是因为 var name 变量 默认为非空的 ,

在 Kotlin 中 不允许将 默认变量 赋值一个空值 ,

除非 将该变量声明为 可空类型 ;

2、声明可空类型变量

声明可空类型变量 :

如果要声明一个 可空类型的变量 , 必须 声明该变量的具体的类型 ,

并在该类型后添加 ? 标志 , 具体格式如下 :


var 变量名: 变量类型?

代码示例 : 在下面的代码张红 ,

var name 变量声明为了 String? 可空类型 ,

此时就可以为 该变量 赋值 null 值 ;


fun main() {
var name: String? = “Tom”
name = null
}

进行了 String? 可空类型声明后 , 在 IntelliJ IDEA 中 , 就不再进行报错了 ;

在这里插入图片描述

三、手动空安全管理


Kotlin 语言中 , 变量类型 分为 可空类型 和 非空类型 ,

默认状态 下 , 变量是 非空类型 的 ,

如果使用 类型? 将变量声明为 可空类型 ,

那么就需要使用 手动安全管理 ;

代码示例 : 在下面的代码中 , 将 name 变量声明为了 String? 可空类型 ,

那么 调用该可空类型变量 的 成员 或 方法 时 , 就不能直接调用了 ,

必须引入 手动安全管理 ;


fun main() {
var name: String? = “Tom”
name.count()
}

上述代码中 , 在调用该变量时 , 就会出现如下报错信息 :


Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?

在这里插入图片描述

四、空安全调用操作符 ?


在 Kotlin 语言中 , 调用 可空类型变量 的 成员 时 ,

可以使用 " 安全调用操作符 " 也就是 ? 进行调用 ,

使用格式如下 :


可空类型变量?.成员

使用了 安全调用操作符 之后 , 在调用变量成员前 , 会自动进行 空值检查 ,

如果该变量为空 , 则会 跳过后面的 成员调用 , 继续执行下一行代码 ;

代码示例 : 在下面的代码中 , 调用 name 变量时 , 使用 ? 安全调用操作符 name?.count() 进行调用 ;


fun main() {
var name: String? = “Tom”
name?.count()
}

在这里插入图片描述

五、let 函数结合空安全调用操作符使用


如果想要在 变量 原有基础上 , 继续执行其它操作 , 可以使用let 标准函数 ;

安全调用操作符 经常与 let 标准函数 一起使用 ;

如 :name?.let{} 方式调用 let 函数 ,

其含义是 如果 name 变量不为空 , 则调用 let 函数 ,

如果 name 变量为空 , 则跳过后面的 let 函数执行 ;

代码示例 : 在下面的代码中 ,

将变量 name 声明为了 可空类型 String? ,

name 变量执行一些 附加操作 时 , 可使用 ?.let{} 方式进行 ,

含义是 , 假如 name 变量不为空 , 则执行 let 函数中的 Lambda 表达式内容 ,

let 函数 返回 匿名函数 最后一行 ,

Lambda 表达式 / 匿名函数 / 闭包 的含义是 ,

如果 name 变量 字符串非空白, 将其转为首字母大写 , 并返回 ,

如果 name 变量 字符串为空白, 设置 Hello 值为返回值 ;


fun main() {
var name: String? = “tom”
name = name?.let {
// let 函数返回 匿名函数 最后一行
if(it.isNotBlank()) {
// 如果字符串非空白, 将其转为首字母大写
it.capitalize()
} else {
// 如果字符串为空白, 设置默认值
“Hello”
}
}
println(name)
}

执行结果 :


Tom

在这里插入图片描述

六、非空断言操作符 !!


Kotlin 中的 可空类型 变量 , 在运行时 可以选择 不启用 安全调用 操作 ,

在调用 可空类型 变量 成员 与 方法 时 , 使用 非空断言操作符 !! ,

如果 可空类型 变量为 空 , 则 直接抛出 空指针异常 KotlinNullPointerException ;

代码示例 : 在下面的代码中 , name 变量是 String? 可空类型 ,

变量值为 null ,

如果使用 name?.count() 的方式调用 , 则会先判定 name 是否为空 , 如果为空则该代码不会执行 ,

如果使用 name!!.count() 的方式调用 , 不会判定 name 是否为空 ,

如果 为空 抛出 KotlinNullPointerException 异常 ;


fun main() {
var name: String? = null
println(name!!.count())
}

执行结果 :


Exception in thread “main” kotlin.KotlinNullPointerException
at HelloKt.main(Hello.kt:3)
at HelloKt.main(Hello.kt)

在这里插入图片描述

七、使用 if 语句判空


在 Kotlin 中 , 对于 可空类型 变量的调用 , 除了使用

  • 空安全调用操作符 ?
  • 非空断言操作符 !!

之外 , 还可以使用 Java 语言中的传统判空方式 ,

if 语句判断 变量 是否为 null ;

空安全调用操作符? 与 使用 if 语句判空操作 对比 :

  • 空安全调用操作符 更加 灵活 , 简洁 ;
  • 空安全调用操作符 可以进行 链式调用 ;

二者的效果是等价的 ;

代码示例 1 : 下面的代码是 使用 if 语句判空 的示例 ;


fun main() {
var name: String? = null
var count: Int? = null
if(name != null) {
count = name.count()
}
println(count)
}

执行结果 :


null

在这里插入图片描述

代码示例 2 : 下面的代码 与 代码示例 1 的 效果是等价的 , 显然本代码更加简洁 ;


fun main() {
var name: String? = null
var count: Int? = name?.count()
println(count)
}

执行结果 :


null

在这里插入图片描述

八、空合并操作符 ?:


空合并操作符?: 用法 :


表达式 A ?: 表达式 B

如果 表达式 A 的值 不为 null , 则 整个表达式的值 就是 表达式 A 的值 ;

如果 表达式 A 的值 为 null , 则 整个表达式的值 就是 表达式 B 的值 ;

代码示例 : 在下面的代码中 ,

name 变量 被声明为 String? 可空类型的变量 , 为其赋值为 null ,

使用 name ?: "name 变量为空" 代码 , 其效果如下 :

空合并操作符 左侧的 name 表达式如果为 null , 则 取 右边的 表达式 作为该表达式最终的值 ,

如果 左侧的 name 表达式 不为 null , 则 取 该 name 变量作为 该表达式最终的值 ;

因此 , 第一次使用 name ?: "name 变量为空" 代码时 , name 为空 , 整个表达式 name ?: "name 变量为空"
返回的是 "name 变量为空" 值 , 打印出来的就是 name 变量为空 内容 ;

之后 为 name 变量赋值 "Tom" 字符串值 , 现在 name 变量不为空 , 使用 name ?: "name 变量为空"
代码返回的是 name 变量的值 , 因此打印出来的就是 Tom 内容 ;


fun main() {
var name: String? = null
println(name ?: “name 变量为空”)

    name = "Tom"
    println(name ?: "name 变量为空")
}
  • 1
  • 2
  • 3

执行结果 :


name 变量为空
Tom

在这里插入图片描述

九、空合并操作符与 let 函数结合使用


空合并操作符 ?: 与 let 函数 结合使用 , 可以 替代 if .. else .. 语句 ;

代码示例 :


fun main() {
var name: String? = null

    name = "tom"
    name = name?.let {
        it.capitalize()
    } ?: "Jerry"

    println(name)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

执行结果 :


Tom

在这里插入图片描述

如果 name 变量为 null , 则 ?: 表达式中 , 会选择 ?: 后面的表达式作为最终结果 ;

对应代码如下 :


fun main() {
var name: String? = null

    name = name?.let {
        it.capitalize()
    } ?: "Jerry"

    println(name)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

执行结果 :


Jerry

在这里插入图片描述

十、空指针异常处理


在 Kotlin 程序中 , 处理异常 的方式有 :

  • 抛出默认异常
  • 抛出自定义异常
  • 捕获并处理异常

1、捕获并处理异常

捕获异常代码示例 : 在下面的代码中 ,

name 变量是可空类型变量 , 其初始值为 null ,

使用 非空断言操作符 !! 调用 变量 成员 , 不会进行 空值检查 ,

如果变量为空 , 则直接抛出 kotlin.KotlinNullPointerException 异常 ;

使用 try .. catch .. 代码块 , 可以捕获并处理异常 ;


import java.lang.Exception

fun main() {
    var name: String? = null

    // 捕获并处理异常
    try {
        name!!.count();
    } catch (e: Exception) {
        println(e)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

执行结果 :


kotlin.KotlinNullPointerException

在这里插入图片描述

2、抛出自定义异常

抛出自定义异常代码示例 : 在下面的代码中 ,

声明了自定义 异常类 MyException , 其继承了 KotlinNullPointerException 空指针异常类 ,

在调用 name 变量成员时 , 先调用 checkNull 函数 ,

检查该变量是否为空 ,

使用 str ?: throw MyException() 代码 , 其中 空合并操作符 判定 str 是否为空 ,

如果为空 , 则抛出 MyException 异常 ;


import java.lang.Exception

fun main() {
    var name: String? = null

    // 捕获并处理异常
    try {
        checkNull(name)
        name!!.count();
    } catch (e: Exception) {
        println(e)
    }
}

fun checkNull(str: String?) {
    str ?: throw MyException()
}

class MyException: KotlinNullPointerException("空指针")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

执行结果 :


MyException: 空指针

十一、先决条件函数判空


1、先决条件函数概念

在 Kotlin 中提供了一些 内置函数 ,

在这些函数中可以抛出 携带自定义信息的异常 ,

这些函数 就是 " 先决条件函数 " ;

只有满足了 先决条件函数 的 先决条件 , 代码才能继续执行 , 否则就会抛异常 ;

2、先决条件函数原型

常用的先决条件函数如下 :

  • checkNotNull 函数 :

    • 参数为 null , 抛出 IllegalStateException 异常 ,
    • 参数为非空 , 返回非空值 ;

    /**

    • 如果[value]为空,则抛出[IllegalStateException]。否则
    • 返回非空值。
    • @sample samples.misc.Preconditions.failCheckWithLazyMessage
      */
      @kotlin.internal.InlineOnly
      public inline fun checkNotNull(value: T?): T {
      contract {
      returns() implies (value != null)
      }
      return checkNotNull(value) { “Required value was null.” }
      }
  • require 函数 :

    • 参数为 false , 抛出 IllegalArgumentException 异常 ;

    /**

    • 如果[value]为false,则抛出[IllegalArgumentException]。
    • @sample samples.misc.Preconditions.failRequireWithLazyMessage
      */
      @kotlin.internal.InlineOnly
      public inline fun require(value: Boolean): Unit {
      contract {
      returns() implies value
      }
      require(value) { “Failed requirement.” }
      }
  • requireNotNull 函数 :

    • 参数为 null , 抛出 IllegalArgumentException 异常 ;
    • 参数非空 , 返回非空值 ;

    /**

    • 如果[value]为空,则抛出[IllegalArgumentException]。否则返回非空值。
      */
      @kotlin.internal.InlineOnly
      public inline fun requireNotNull(value: T?): T {
      contract {
      returns() implies (value != null)
      }
      return requireNotNull(value) { “Required value was null.” }
      }
  • error 函数 :

    • 参数为 null , 使用给定的 错误信息 抛出 IllegalStateException 异常 ;
    • 参数非空 , 返回非空值 ;

    /**

    • 使用给定的[message]抛出[IllegalStateException]。
    • @sample samples.misc.Preconditions.failWithError
      */
      @kotlin.internal.InlineOnly
      public inline fun error(message: Any): Nothing = throw IllegalStateException(message.toString())
  • assert 函数 :

    • 参数为 false , 抛出 AssertionError 异常 , 并进行 断言标记 ;

    /**

    • 如果[value]为false,则抛出[AssertionError]
    • 和运行时断言已经使用*-ea* JVM选项在JVM上启用。
      */
      @kotlin.internal.InlineOnly
      public inline fun assert(value: Boolean) {
      assert(value) { “Assertion failed” }
      }

3、先决条件函数代码示例

代码示例 : 在执行 name 字符串的 count 函数之前 ,

先使用 checkNotNull(name, {"变量为空"}) 先决条件函数 , 判定 name 是否为空 ,

如果为空 , 抛出带信息的 IllegalStateException 异常 信息 ;


fun main() {
var name: String? = null

    // 捕获并处理异常
    try {
        checkNotNull(name, {"变量为空"})
        name!!.count();
    } catch (e: Exception) {
        println(e)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

执行结果 :


java.lang.IllegalStateException: 变量为空

在这里插入图片描述

上述使用的 先决条件函数checkNotNull 原型 :


/**
* 如果[value]为空,则使用调用[lazyMessage]的结果抛出[IllegalStateException]。否则
* 返回非空值。
*
* @sample samples.misc.Preconditions.failCheckWithLazyMessage
*/
@kotlin.internal.InlineOnly
public inline fun checkNotNull(value: T?, lazyMessage: () -> Any): T {
contract {
returns() implies (value != null)
}

    if (value == null) {
        val message = lazyMessage()
        throw IllegalStateException(message.toString())
    } else {
        return value
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

学习网络安全技术的方法无非三种:

第一种是报网络安全专业,现在叫网络空间安全专业,主要专业课程:程序设计、计算机组成原理原理、数据结构、操作系统原理、数据库系统、 计算机网络、人工智能、自然语言处理、社会计算、网络安全法律法规、网络安全、内容安全、数字取证、机器学习,多媒体技术,信息检索、舆情分析等。

第二种是自学,就是在网上找资源、找教程,或者是想办法认识一-些大佬,抱紧大腿,不过这种方法很耗时间,而且学习没有规划,可能很长一段时间感觉自己没有进步,容易劝退。

第三种就是去找培训。

image.png

接下来,我会教你零基础入门快速入门上手网络安全。

网络安全入门到底是先学编程还是先学计算机基础?这是一个争议比较大的问题,有的人会建议先学编程,而有的人会建议先学计算机基础,其实这都是要学的。而且这些对学习网络安全来说非常重要。但是对于完全零基础的人来说又或者急于转行的人来说,学习编程或者计算机基础对他们来说都有一定的难度,并且花费时间太长。

第一阶段:基础准备 4周~6周

这个阶段是所有准备进入安全行业必学的部分,俗话说:基础不劳,地动山摇
image.png

第二阶段:web渗透

学习基础 时间:1周 ~ 2周:

① 了解基本概念:(SQL注入、XSS、上传、CSRF、一句话木马、等)为之后的WEB渗透测试打下基础。
② 查看一些论坛的一些Web渗透,学一学案例的思路,每一个站点都不一样,所以思路是主要的。
③ 学会提问的艺术,如果遇到不懂得要善于提问。
image.png

配置渗透环境 时间:3周 ~ 4周:

① 了解渗透测试常用的工具,例如(AWVS、SQLMAP、NMAP、BURP、中国菜刀等)。
② 下载这些工具无后门版本并且安装到计算机上。
③ 了解这些工具的使用场景,懂得基本的使用,推荐在Google上查找。

渗透实战操作 时间:约6周:

① 在网上搜索渗透实战案例,深入了解SQL注入、文件上传、解析漏洞等在实战中的使用。
② 自己搭建漏洞环境测试,推荐DWVA,SQLi-labs,Upload-labs,bWAPP。
③ 懂得渗透测试的阶段,每一个阶段需要做那些动作:例如PTES渗透测试执行标准。
④ 深入研究手工SQL注入,寻找绕过waf的方法,制作自己的脚本。
⑤ 研究文件上传的原理,如何进行截断、双重后缀欺骗(IIS、PHP)、解析漏洞利用(IIS、Nignix、Apache)等,参照:上传攻击框架。
⑥ 了解XSS形成原理和种类,在DWVA中进行实践,使用一个含有XSS漏洞的cms,安装安全狗等进行测试。
⑦ 了解一句话木马,并尝试编写过狗一句话。
⑧ 研究在Windows和Linux下的提升权限,Google关键词:提权
image.png
以上就是入门阶段

第三阶段:进阶

已经入门并且找到工作之后又该怎么进阶?详情看下图
image.png

给新手小白的入门建议:
新手入门学习最好还是从视频入手进行学习,视频的浅显易懂相比起晦涩的文字而言更容易吸收,这里我给大家准备了一套网络安全从入门到精通的视频学习资料包免费领取哦!

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号