1、使用 ?. 来进行安全调用
使用 ?. 可以安全的调用可空类型的方法和属性,如果为空那么返回null,否则调用对应的方法或者属性。
val b: String? = nullprintln(b?.toUpperCase())
这个例子中, b?.toUpperCase() 如果 b 不为 null,那么返回b.toUpperCase(), 否则返回 null , b?.toUpperCase 的型是 String? 。
对于嵌套比较深的复杂对象,使用 ?. 能够方便的进行链式调用。
user?.name?.firstName?.toUpperCase()
中间任意一个属性或者方法为 null 那么整个表达式就返回 null 。
2、三元操作符 ?:
对于一个可空变量,很多时候我们希望可以在不为空时直接使用对应的值,空时使用默认值, ?: 操作符可以实现对应的效果。
val l = b?.length ?: -1
?: 左边的部分不为 null 时 ?: 返回对应的值,否则返回右边的值另外 ?: 也遵循短路原则,如果左边的值不为 null 右边的表达式是会执行的。
在函数中, ?: 可以用来提前从函数中退出。
fun foo(node: Node): String? { val parent = node.getParent() ?: return null val name = node.getName() ?: throw IllegalArgumentException(“name expected”) // …}
3、lateinit
通常 kotlin 类里的非空属性必须在构造期间初始化,但是很多时候我们会过其他方式来完成赋值操作,比如依赖注入(@Inject, @Autowired),单元测试的 setup 方法, @PostConstruct 等。这时如果我们属性声明为可空类型就会带来很多的麻烦,使用时都要做可空判断或者使用!! ,非常的不方便。
这种场景下,我们可以使用 lateinit 关键词来修饰属性,来避免null 相关检查。
class UserController() { @Resource private lateinit var userService: UserService @GetMapping(“/users/{uid}”) fun getUserFavPostList(@PathVariable(“uid”) uid: uid): User { return userService.getUserInfo(uid) // 不需要空判断 }}
lateinit 使用有一定的条件限制,只能修饰 var 声明的属性,并且能有自定义的 getter/setter ,只能用在 class body 中的属性在 primary constructor 中的不可用。如果在属性初始化之前使用变量然会抛出 NPE ,从1.2开始,可以使用 isInitialized 来检查lateinit var 是否被初始化。
if (this::userService.isInitialized) { println(userService.getUserInfo(uid))}
lateinit 的实现是基于 kotlin 的属性委托,使用 notNull 也以达到类似的效果。
4、非安全操作符 !!
!! 会忽略变量的类型,强制转换为非空类型,但是这个操作符是不安的,如果变量为 null 那么会抛出 NPE 。
val upper = b!!.toUpperCase()
