# null和null安全

## 非空类型和可空类型

Kotlin 系统类型分为可空类型和不可空类型。 Kotlin 中引入了可空类型，把有可能为 null 的值单独用可空类型来表示。这样就在可空引用与不可空引用之间划分出一条明确的、 显式的“界线”。

在Kotlin中，在定义变量时，给变量类型后增加`?`后缀，来标记类型是否可为空：

```kotlin
var str = "hahaha"
// toIntOrNull方法：str 转换 int，如果转换失败，则转换为null
var num: Int = str.toIntOrNull()  // 无法通过编译
var num: Int? = str.toIntOrNull() // 能够通过编译
println(num)
```

上述代码`Int?`就是一个可空类型，可以给他一个null值。

## 可空类型必须判断才能使用

可空类型的变量不允许直接调用方法或属性，但可以先判断该变量不为 null，然后再调用 该变量的方法或属性。

```kotlin
var a :String? = ""

// a.toBigDecimal() // 直接调用报错
if (a != null) {
    a.toBigDecimal()
}
```

对于Boolean类型：

```kotlin
var b: Boolean? = null
// 以下代码正确
if(b == true){
    println("为真")
}

// 以下代码报错，null不能作为条件
if (b) {
    println("为真")
}
```

## 安全调用

```kotlin
// 如果item不为空，才调用let函数
item?.let { println(it) }
```

## 强制调用

Kotlin 用 “!!.” 即可强制调用可空变量的方法或属性，这样强制调用可能引发 NPE：

```kotlin
item!!.let { println(it) }
```

## Elvis运算

Elvis运算是一种if-else的简化写法：

```kotlin

var b: String? = "Kotlin"
// 先判断 b 不为 null，然后访问 b 的 length 属性
var len1 = if (b != null) b.length else -1
println(len1)  // 输出 6
b = null

// 使用 Elvis 运算符， 如果b不等于null，返回长度，否则返回-1
var len2 = b?.length ?: -1
println(len2)  // 输出 -1
```
