【Kotlin 初学者】空安全与异常

举报
帅次 发表于 2021/12/23 00:38:51 2021/12/23
【摘要】 作者简介:CSDN博客专家、华为云享专家认证 系列专栏:Kotlin 初学者 学习交流:三人行必有我师焉;择其善者而从之,其不善者而改之。 目录 一、空安全 1.1 空指针 1.2 可空性(?) 1.3 安全调用操作符(?.) 1.4 let操作符 1.5 使用非空断言操作符(!!.) 1.6 使用空合...

作者简介:CSDN博客专家、华为云享专家认证

系列专栏:Kotlin 初学者

学习交流:三人行必有我师焉;择其善者而从之,其不善者而改之。

目录

一、空安全

1.1 空指针

1.2 可空性(?)

1.3 安全调用操作符(?.)

1.4 let操作符

1.5 使用非空断言操作符(!!.)

1.6 使用空合并操作符(?:)

1.7 使用类型转换操作符(as)

1.7.1 不安全的转换操作符:as

1.7.8 安全转换操作符:as?

二、异常

2.1 概念

2.2 try...catch块

2.2.1 使用catch块的try语法

2.2.2 使用finally块的try语法

2.2.3 try catch语法与finally块

2.3 finally块

2.4 throw关键字

2.5 先决条件


一、空安全

1.1 空指针

        在Java中,定义一个变量可以默认不赋值,因为Java的系统会给我们默认赋一个默认值,并且Java可定义一个赋值为null的变量,这样在使用这个变量的时候都会去显示判断该变量是否为null。这使得在Java中我们司空见惯的空指针异常NullPointerException,带给了我们很多麻烦。

        Kotlin 的类型系统旨在从我们的代码中消除 NullPointerException。

NPE 的唯一可能的原因可能是:

  • 显式调用 throw NullPointerException()

  • 使用了下文描述的 !! 操作符

  • 外部 Java 代码导致的

  • 对于初始化,有一些数据不一致(如一个未初始化的 this 用于构造函数的某个地方)

        除非另有规定,变量不可为null值,这样一来,运行时崩溃从根源上得到解决。如下图,报错:变量"name"必须初始化

1.2 可空性(?)

        Kotlin区分可空类型和非可空类型,所以,你要一个可空类型变量运行,而它又可能不存在,对于这种潜在危险,编译器时刻警惕着。为了应对这种风险,Kotlin不允许你在可空类型值上调用函数,除非你主动接手安全管理。如下图:

        那么完美如何使得变量变为可空类型。

定义一个可空类型的变量的格式为:修饰符 变量名 :类型? = 值


  
  1. fun main() {
  2.     //可空性
  3.     //数据类型后面加"?",表示可为该数据类型或者为null
  4.     var age :Int? = 15
  5.     age = null//未报错
  6. }

1.3 安全调用操作符(?.)

  • 可空类型变量?.属性/函数。如果可空类型变量为null时,返回null

  • 能有效避免空引用异常(NullPointException),因为只要链式其中的一个为null,则整个表达式都为null

        当使用可用类型调用函数调用函数时必须使用安全调用操作符(?.),否则编译都不通过。


  
  1.     //安全调用操作符
  2.     println(age?.plus(20))//null

函数中使用可空类型

        当一个函数有返回值时,如果函数中的代码使用 ?. 去返回一个值,那么函数的返回值的类型后面也要加上?符号。


  
  1. //返回值Int为可空
  2. fun userInfo() : Int? {
  3.     //name 为可空的String类型属性
  4.     var name:String?="Java"
  5.     name=null
  6.     //使用安全调用操作符(?.)
  7.     return name?.length
  8. }

1.4 let操作符

let的用法:变量?.let{ … }

let操作符的作用:当时用符号?.验证的时候忽略掉null

        安全调用允许在可空类型上调用函数,但是如果还想做点额外的事,比如创建新值,或判断不为null就调用其他函数,怎么办?可以使用带let函数的安全调用操作符。你可以在任何类型上调用let函数,它的主要作用是让你在指定的作用域内定义一个或多个变量。


  
  1.     //let
  2.     var typeString? = "java"
  3.     type = type?.let {
  4.         if (it.isNotBlank()) {
  5.             "$it,非空白字符串"
  6.         }else{
  7.             "Kotlin"
  8.         }
  9.     }
  10.     println(type)
  11.     type = ""//空字符
  12.     type = type?.let {
  13.         if (it.isNotBlank()) {
  14.             "$it,非空白字符串"
  15.         }else{
  16.             "Kotlin"
  17.         }
  18.     }
  19.     println(type)

1.5 使用非空断言操作符(!!.)

!!. 又称感叹号操作符,当变量值为null时,会抛出NullPointerException


  
  1.     //非空断言操作符
  2.     type = null
  3.     println(type!!.toString())

1.6 使用空合并操作符(?:)

?:操作符的意思是,如果左边的求值结果为null,就使用右边的结果值。


  
  1.     type = null
  2. //    println(type!!.toString())//空指针异常
  3.     println("------------")
  4.     //空合并操作符(?:)
  5.     //当type为空是,运行打印"Kotlin"
  6.     println(type ?: "Kotlin")
  7.     type = "Java"
  8.     //当type 为"Java"是,运行打印"Java"
  9.     println(type ?: "Kotlin")

使用?:+let代替if/else


  
  1.     println("---?:+let----")
  2.     type = ""
  3.     type = type?.let { "Kotlin" }?:"Java"
  4.     println(type)
  5.     type = null
  6.     type = type?.let { "Kotlin" }?:"Java"
  7.     println(type)

1.7 使用类型转换操作符(as)

1.7.1 不安全的转换操作符:as

        有时无法转换变量并抛出异常,这称为不安全转换。不安全的强制转换由中缀运算符执行。

        可以为空的字符串(String?)不能转换为非null Int类型,这会引发异常。


  
  1.     var asTest :String? = ""
  2.     //不安全的转换操作符
  3.     println(asTest as Int)

Exception in thread "main" java.lang.ClassCastException:


  
  1. Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
  2.  at com.scc.kotlin.primary.NullKt.main(Null.kt:64)
  3.  at com.scc.kotlin.primary.NullKt.main(Null.kt)

1.7.8 安全转换操作符:as?

        as?安全地转换成一种类型。 如果无法进行转换,则返回null,而不是抛出ClassCastException异常。

        咱就在上面的实例基础上修改。


  
  1.     var asTest :String? = ""
  2.     //不安全的转换操作符 as
  3. //    println(asTest as Int)//ClassCastException
  4.     //安全的转换操作符 as?
  5.     println(asTest asInt)//null

二、异常

2.1 概念

        异常是程序中发生的运行时问题导致程序终止。这可能是由于内存空间不足,数组越界,条件除以零而发生的。要在程序执行期间处理这种类型的问题,可使用异常处理技术。 异常处理是一种处理运行时问题并维护程序执行流程的技术。 在Kotlin中,所有异常类都是Throwable类的子类。 要抛出异常对象,Kotlin使用throw表达式。

异常处理中使用了四种不同的关键字。它们是:

  • try:try块包含可能生成异常的语句集。必须后跟catch 或 finally或两者。

  • catch:catch块用于捕获try块抛出的异常。

  • finally:finally块始终执行是否处理异常。所以它用于执行重要的代码语句。

  • throw:throw关键字用于显式抛出异常。

Kotlin的异常处理和Java类似。

未经检查的异常

                未经检查的异常是由于代码中的错误而引发的异常。此异常类型扩展了RuntimeException类。在运行时检查未经检查的异常。 以下是未经检查的异常的一些示例:

  • ArithmeticException :当将数字除以零时抛出。

  • ArrayIndexOutOfBoundExceptions:尝试使用不正确的索引值访问数组时抛出。

  • SecurityException:由安全管理器抛出以指示安全性违规。

  • NullPointerException:在null对象上调用方法或属性时抛出。

注意:Kotlin不支持已检查异常。

2.2 try...catch块

        try-catch块用于代码中的异常处理。 try块包含可能抛出异常的代码,catch块用于处理异常,必须在方法中写入此块。try块必须跟随catch块或finally块或两者。

2.2.1 使用catch块的try语法


  
  1. fun main() {
  2.     var name: String? = null
  3.     try {
  4.         name!!.plus("is good")//报错:NullPointerException
  5.     } catch (e: NullPointerException) {
  6.         println(e.message)
  7.     }
  8. }

2.2.2 使用finally块的try语法


  
  1.     var nameString? = null
  2.     try {
  3.         name!!.plus("is good")//报错:NullPointerException
  4.     } finally {
  5.         println("都结束了")
  6.     }

2.2.3 try catch语法与finally块


  
  1.     var nameString? = null
  2.     try {
  3.         name!!.plus("is good")//报错:NullPointerException
  4.     } catch (eNullPointerException) {
  5.         println(e.message)
  6.     } finally {
  7.         println("都结束了")
  8.     }

2.3 finally块

        finally是这样的块:无论是否处理异常,它总是执行。所以它用于执行重要的代码语句。如下:

        如上面代码,已产生异常,但是finally块中的代码还是执行了。

注意:如果程序退出(通过调用exitProcess(Int)或导致进程中止的任何错误),将不执行finally块。

2.4 throw关键字

        throw关键字用于抛出显式异常。它用于抛出自定义异常。要抛出异常对象,将使用throw-expression。


  
  1. fun main() {
  2.     try {
  3.         //第三步:使用
  4.         checkData(name)
  5.         name!!.plus("is good")//报错:NullPointerException
  6.     } catch (e: Exception) {
  7.         println(e.message)
  8.     }
  9. }
  10. //第二步:传入可空String
  11. fun checkData(str:String?){
  12.     //当str为空时,执行ScException()
  13.     str?:throw ScException()
  14. }
  15. //第一步:自定义异常
  16. class ScException():IllegalArgumentException("帅次牌异常")

2.5 先决条件

        Kotlin中提供一些遍历的内置函数,使用这些函数可以自定义信息的异常,这些函数就是先决条件函数。可以用该种函数自定义先决条件,当满足条件时代码才会执行。

函数 描述
checkNotNull 如果参数为null,则抛出IllegalArgumentException异常,否则返回非空值
require 如果参数为false,则抛出IllegalArgumentException异常
requireNotNull 如果参数为null,则抛出IllegalArgumentException异常,否则返回非空值
error 如果参数为null,则抛出IllegalArgumentException异常并输出错误信息,否则返回非空值
assert 如果参数为false,则抛出AssertError异常,并打上断言编译器标记

  
  1.     try {
  2.         //第三步:使用
  3.         checkData(name)
  4.         name!!.plus("is good")//报错:NullPointerException
  5.     } catch (e: Exception) {
  6.         println(e.message)
  7.     }
  8. }
  9. //第二步:传入可空String
  10. fun checkData(str:String?){
  11.     //当str为空时,执行lambda表达式
  12.     checkNotNull(str,{"帅次牌先决条件异常"})
  13. }

文章来源: shuaici.blog.csdn.net,作者:帅次,版权归原作者所有,如需转载,请联系作者。

原文链接:shuaici.blog.csdn.net/article/details/122056385

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。