🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### **?:( Elvis操作符)** 在使用安全调用符调用可空变量中的成员方法或属性时,如果当前变量为空,则会返回一个null值,但**有时即使当前变量为null,也不想返回一个null值而是指定一个默认值,此时该如何处理呢**?为了解决这样的问题,Kotlin中提供了一个Elvis操作符(?:),通过Elvis操作符(?:)可以指定可空变量为null时,调用该变量中的成员方法或属性的返回值,其语法格式为“`表达式?:表达式`”。如果左侧表达式非空,则返回左侧表达式的值,否则返回右侧表达式的值。当且仅当左侧为空时,才会对右侧表达式求值。 ![](https://box.kancloud.cn/9444244dc466c89cd85eadbb6b1ef293_463x154.png) Elvis 运算符接收两个运算数,如果第一个运算数不为null ,运算结果就是第一个运算数;如果第一个运算数为null ,运算结果就是第二个运算数 Kotlin中没有这样的三元运算符`true?1:0`,取而代之的是`if(true) 1 else 0`。而Elvis操作符算是精简版的三元运算符。 用Elvis操作符(?:)可以把带有默认值的if/else结构写的及其短小。用Elvis操作符不用检查null(避免了`NullPointerException`),也不用重复变量。 针对【变量?.方法】,如果变量为NULL,【变量?.方法】的返回结果是NULL,那我们**能不能指定想返回的值呢**? 答案是肯定的,我们**需要配合Elvis操作符**,使用方式为【**变量?:值** 】。参考代码: ~~~ fun main(args: Array<String>) { //可空类型变量 var age: String? = null //使用安全调用符 val result = age?.toInt() ?: "age为null" //打印结果 println(result) } ~~~ 运行结果 ``` age为null Process finished with exit code 0 ``` * 使用Elvis操作符的一行代码更换为如下代码 ``` val result = age?.toInt() ?: 0 ``` 那么运行结果就是 ``` 0 Process finished with exit code 0 ``` * 使用Elvis操作符的一行代码更换为如下代码 ``` val result = age?.toInt() ?: throw NumberFormatException() ``` 运行结果如下 ``` Exception in thread "main" java.lang.NumberFormatException at day02.ElvisDemoKt.main(ElvisDemo.kt:14) Process finished with exit code 1 ``` **Elvis 运算符经常和安全调用运算符一起使用**,用一个值代替对null 对象调用方法时返回的null,如下代码 ~~~ fun main(args: Array<String>) { fun strLenSafe(s:String?):Int=s?.length ?:0 println(strLenSafe("abc")) println(strLenSafe(null)) } ~~~ 运行结果 ``` 3 0 Process finished with exit code 0 ``` 在Kotlin 中有一种场景下Elvis 运算符会特别顺手,像return 和throw 这样的操作其实是表达式,因此可以把它们写在Elvis 运算符的右边。这种情况下,如果Elvis 运算符左边的值为null ,函数就会立即返回一个值或者抛出一个异常。如果函数中需要检查先决条件,这个方式特别有用。 ~~~ /** * 同时使用throw和Elvis运算符 */ import java.lang.IllegalArgumentException class Address1(val streetAddress:String,val zipCode:Int,val city:String,val country:String) class Company1(val name:String,val address: Address1?) class Person1(val name: String,val company: Company1?) fun printShippingLabel(person1: Person1){ val address1=person1.company?.address?:throw IllegalArgumentException("No Address")//如果缺少address1就抛出异常 with(address1){//"address1"不为空 println(streetAddress) println("$zipCode $city,$country") } } fun main(args: Array<String>) { val address1=Address1("Elsestr.47",80687,"Munich","Germany") val jetbrains=Company1("JetBrains",address1) val person1=Person1("Dmitry",jetbrains) printShippingLabel(person1) printShippingLabel(Person1("Alexey",null)) } ~~~ 运行结果 ``` Elsestr.47 80687 Munich,Germany Exception in thread "main" java.lang.IllegalArgumentException: No Address at A基础.ElvisDemoKt.printShippingLabel(ElvisDemo.kt:13) at A基础.ElvisDemoKt.main(ElvisDemo.kt:26) Process finished with exit code 1 ``` >[info]PS:如果一切正常,函数printShippingLabel会打印出标签。如果地址不存在,它不会只是抛出一个带行号的NullPointerException ,相反,它会报告一个有意义的错误。如果地址存在,标签会包含街道地址、邮编、城市和国家。