在Kotlin中!!跟?都是用于判断空参数异常的

?意思是这个参数可以为空,并且程序继续运行下去
!!的意思是这个参数如果为空,就抛出异常

(1)?(安全调用)

下面给大家举个简单的例子,在JAVA中判断一个参数非空是这样写的:

NullClass nullClass = null;
        
if (nullClass!=null) {如果判断为空
    ullClass.nullFun();//跳过这一行,程序继续执行
 }

//转换成kotlin之后
val nullClass: NullClass? = null
nullClass?.nullFun()

在一开始的时候我们声明了一个类,并且在类名后面加了一个? 意思就是这个类可以为空,然后在下面用到这个类里面的一个方法时又加了一个问号,意思就是,当程序运行到这一行时,如果这个参数为空,就跳过这一行,程序继续执行下去。

所以?的用法就是相当于Java里的if()判断null

(2)!!

val nullClass: NullClass?=null
nullClass!!.nullFun()

//转换成Java如下:
NullClass nullClass = null;
        
if (nullClass!=null) {//如果判断为空
    nullClass.nullFun();
}else {//抛出空参数异常
    throw new NullPointerException();
}

这里大家应该都能看明白了,在第二行参数后面加个!!,意思就是当程序执行到这行,判断这个参数如果是空参数,就抛出异常。

  • 使用 ?时,程序会进行非空判断,如为空,则返回 null ,不会造成程序报错。但注意返回的是 null 而非 0
  • 使用 !! 时,会对对象进行非空判断,并且会像 java 代码一样抛出异常

(3)?:(Elvis运算)

fun main(args : Array<String>){
	var b:String? = "fkit"
	var lenl = if (b != null) b.length else -1
	println(lenl)
	b = null
	var len2 = b?.length ?: -1
	println(len2)
}

如果"?:"符号左边的表达式不为null,则返回左边表达式的值,否则返回右边表达式的值。

(4)::

Kotlin 中 双冒号操作符 表示把一个方法当做一个参数,传递到另一个方法中进行使用,通俗的来讲就是引用一个方法。

//lock 函数 的第三个参数传入 method 时,要确定参数个数、类型、返回值都和其形参一致
fun main(args: Array<String>) {
    println(lock("param1", "param2", ::getResult))
}

/**
 * @param str1 参数1
 * @param str2 参数2
 */
fun getResult(str1: String, str2: String): String = "result is {$str1 , $str2}"

/**
 * @param p1 参数1
 * @param p2 参数2
 * @param method 方法名称
 */
fun lock(p1: String, p2: String, method: (str1: String, str2: String) -> String): String {
    return method(p1, p2)
}

//result
result is {param1 , param2}

如果我们需要调用其他 Class 中的某一个方法是:

fun main(args: Array<String>) {
    var d = Test()
    println(lock("param1", "param2", d::getResult))
}

在 Class 中的某个方法中使用双冒号调用当前 Class 的内部方法时调动方式为:

class Test1 {
    fun isOdd(x: Int) = x % 2 != 0

    fun test() {
        var list = listOf(1, 2, 3, 4, 5)
        println(list.filter(this::isOdd))
    }
}

一般情况,我们调用当前类的方法 this 都是可省略的,这里之所以不可省略的原因是:

为了防止作用域混淆 ,::调用的函数如果是类的成员函数或者是扩展函数,必须使用限定符,比如this

如果把 isOdd 写到 class 外部 (全局) 这里也是可以省略限定符。

(5)->(函数类型)

(6)== 和 ===

//code1
fun main(args: Array<String>) {
	val a : Int = 1000
	println(a == a) //true
	println(a === a) //true
	val a1 : Int = a
	val a2 : Int = a
	println(a1 == a2) //true
	println(a1 === a2) //true
}
//=== 表示比较对象地址,== 表示比较两个值大小。
//所以无论是 a == a 还是 a === a 都是返回true,因为是同一个变量,数值大小和地址都是相等的。

//code2
fun main(args: Array<String>) {
	val a : Int = 1000
	println(a == a) //true
	println(a === a) //true
	val a1 : Int? = a
	val a2 : Int? = a
	println(a1 == a2) //true
	println(a1 === a2) //false
}
//code1中a1 和 a2 都没有装箱,所以不是对象,只是数值,所以数值大小和地址都是相等的。
//code2中a1 和 a2 涉及到装箱,已经变成了对象,此时它们的数值仍然相等,但地址已经不同了(因为是不同对象)。

//code3
fun main(args: Array<String>) {
	val a : Int? = 1000
	println(a == a) //true
	println(a === a) //true
	val a1 : Int? = a
	val a2 : Int? = a
	println(a1 == a2) //true
	println(a1 === a2) //true
}
//此时a1和a2指的是同一个对象(对象a)。既然是同一个对象,那么数值大小和地址肯定都是相等的

//code4
fun main(args: Array<String>) {
	val a : Int = 100
	println(a == a) //true
	println(a === a) //true
	val a1 : Int? = a
	val a2 : Int? = a
	println(a1 == a2) //true
	println(a1 === a2) //true
}
//在范围是 [-128, 127] 之间的数装箱时并不会创建新的对象,所以这里a1和a2装箱后的对象是同一个,a1 === a2也就返回true了。
//这里改为128或-129就又会变成false了。