Kotlin和惯用的方式来写,'如果不是空的,否则…'基于可变值

假设我们有这样的代码:

class QuickExample { fun function(argument: SomeOtherClass) { if (argument.mutableProperty != null ) { doSomething(argument.mutableProperty) } else { doOtherThing() } } fun doSomething(argument: Object) {} fun doOtherThing() {} } class SomeOtherClass { var mutableProperty: Object? = null } 

与Java不同的是,在运行时你可以独自担心空引用问题,但是这并不能正确编译。 当然, mutableProperty在'if'中可能不再是null。

我的问题是处理这个问题的最好方法是什么?

有几个选项是显而易见的。 在不使用任何新的Kotlin语言功能的情况下,最简单的方法显然是将该值复制到一个方法范围的值,而后者不会随之改变。

有这个:

 fun function(argument: SomeOtherClass) { argument.mutableProperty?.let { doSomething(it) return } doOtherThing() } 

这有一个明显的缺点,就是你需要尽早返回或者避免执行后面的代码 – 在某些小的上下文中可以,但是却有一定的异味。

那么有这种可能性:

 fun function(argument: SomeOtherClass) { argument.mutableProperty.let { when { it != null -> { doSomething(it) } else -> { doOtherThing() } } } } 

但是它的目的明确性更高,可以说它比Java处理这种方式更加笨拙和冗长。

我错过了什么,是否有一个成功的成语呢?

我不相信有一个真正的“短”的方式来实现它,但是你可以简单地使用一个条件在或let

 with(mutableVar) { if (this != null) doSomething(this) else doOtherThing() } mutableVar.let { if (it != null) doSomething(it) else doOtherThing() } 

这相当于你的声明。

总是有你描述的选项,把它分配给一个变量:

 val immutable = mutableVar if (immutable != null) { doSomething(immutable) } else { doOtherThing() } 

在情况变得太冗长的情况下,这总是一个很好的回退。

有可能没有一个非常好的方法来实现这一点,因为只有最后一个 lambda参数被允许放在()之外,所以指定两个不会真的适合所有其他标准函数的语法。

可以写一个,如果你不介意的话(或者你会传递方法引用):

 inline fun <T : Any, R> T?.ifNotNullOrElse(ifNotNullPath: (T) -> R, elsePath: () -> R) = let { if(it == null) elsePath() else ifNotNullPath(it) } 

我会用与猫王运营商 。

 mutableProperty?.let { doSomething(it) } ?: doOtherThing() 

从文档:

如果?:左边的表达式不为空,则elvis运算符返回它,否则返回右边的表达式。 请注意,右侧的表达式只有在左侧为空时才被评估。

对于右边表达式之后的一段代码:

  mutableProperty?.let { doSomething(it) } ?: run { doOtherThing() doOtherThing() }