假设我有activities
类型的变量List<Any>?
。如果列表不为空且不为空,我想做某事,否则我想做其他事情。我提出了以下解决方案:
when {
activities != null && !activities.empty -> doSomething
else -> doSomethingElse
}
在Kotlin中有更多惯用的方法吗?
答案 0 :(得分:28)
对于一些简单的操作,您可以使用安全调用操作符,假设操作也不考虑在空列表上操作(处理两者 null和空的情况:
myList?.forEach { ...only iterates if not null and not empty }
其他行动。您可以编写一个扩展函数 - 两种变体,具体取决于您是希望将列表作为this
接收还是作为参数:
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
}
inline fun <E: Any, T: Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
func(this)
}
}
您可以将其用作:
fun foo() {
val something: List<String>? = makeListOrNot()
something.withNotNullNorEmpty {
// do anything I want, list is `this`
}
something.whenNotNullNorEmpty { myList ->
// do anything I want, list is `myList`
}
}
你也可以做反函数:
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func: () -> Unit): Unit {
if (this == null || this.isEmpty()) {
func()
}
}
我会避免将这些链接起来,因为那时你用更加罗嗦的东西替换if
或when
语句。而且您正在进一步了解我在下面提到的替代方案提供的领域,这是成功/失败情况的完全分支。
注意:这些扩展被推广到持有非空值的Collections
的所有后代。并且不仅仅是列表。
<强>备选方案:强>
Kotlin的Result库提供了一个很好的方法来处理你的情况,或者那个&#34;基于响应值。对于Promises,您可以在Kovenant库中找到相同的内容。
这两个库都为您提供了从单个函数返回替代结果的方式,以及基于结果分支代码的方式。 他们确实要求您控制&#34;答案的提供者&#34;被采取行动。
这些是Optional
和Maybe
的好Kotlin替代品。
探索扩展功能进一步(可能太多)
此部分只是为了表明当您遇到类似此处提出的问题的问题时,您可以在Kotlin中轻松找到许多答案,以便按照您希望的方式进行编码。如果世界不可思议,改变世界。它不是一个好的或坏的答案,而是其他信息。
如果您喜欢扩展函数并想考虑将它们链接到表达式中,我可能会将它们更改为如下...
返回withXyz
this
和whenXyz
的{{1}}风格应该返回一个新类型,允许整个集合成为一个新的集合(甚至可能与原始集合无关)。产生如下代码:
val BAD_PREFIX = "abc"
fun example(someList: List<String>?) {
someList?.filterNot { it.startsWith(BAD_PREFIX) }
?.sorted()
.withNotNullNorEmpty {
// do something with `this` list and return itself automatically
}
.whenNotNullNorEmpty { list ->
// do something to replace `list` with something new
listOf("x","y","z")
}
.whenNullOrEmpty {
// other code returning something new to replace the null or empty list
setOf("was","null","but","not","now")
}
}
注意:此版本的完整代码位于帖子的末尾(1)
但是你也可以通过自定义&#34来全新的方向;否则就是#34;机构:
fun foo(someList: List<String>?) {
someList.whenNullOrEmpty {
// other code
}
.otherwise { list ->
// do something with `list`
}
}
没有限制,具有创造性并学习扩展的力量,尝试新的想法,正如您所看到的,人们希望如何编码这些类型的情况有很多变化。 stdlib不能支持这些类型的方法的8种变体而不会混淆。但是每个开发组都可以使用与其编码风格相匹配的扩展。
注意:此版本的完整代码位于帖子的末尾(2)
示例代码1: 以下是&#34;链接&#34;的完整代码版本 强>
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): T? {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNotNullNorEmpty(func: (T) -> R?): R? {
if (this != null && this.isNotEmpty()) {
return func(this)
}
return null
}
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func: () -> Unit): T? {
if (this == null || this.isEmpty()) {
func()
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNullOrEmpty(func: () -> R?): R? {
if (this == null || this.isEmpty()) {
return func()
}
return null
}
示例代码2: 以下是&#34的完整代码;否则就是&#34;库(带单元测试):
inline fun <E : Any, T : Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
with (this) { func() }
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
func(this)
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.withNullOrEmpty(func: () -> Unit): OtherwiseWithValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWithValueIgnore<T>()
} else {
OtherwiseWithValueInvoke(this)
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNullOrEmpty(func: () -> Unit): OtherwiseWhenValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWhenValueIgnore<T>()
} else {
OtherwiseWhenValueInvoke(this)
}
}
interface Otherwise {
fun otherwise(func: () -> Unit): Unit
}
object OtherwiseInvoke : Otherwise {
override fun otherwise(func: () -> Unit): Unit {
func()
}
}
object OtherwiseIgnore : Otherwise {
override fun otherwise(func: () -> Unit): Unit {
}
}
interface OtherwiseWithValue<T> {
fun otherwise(func: T.() -> Unit): Unit
}
class OtherwiseWithValueInvoke<T>(val value: T) : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
with (value) { func() }
}
}
class OtherwiseWithValueIgnore<T> : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
}
}
interface OtherwiseWhenValue<T> {
fun otherwise(func: (T) -> Unit): Unit
}
class OtherwiseWhenValueInvoke<T>(val value: T) : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
func(value)
}
}
class OtherwiseWhenValueIgnore<T> : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
}
}
class TestBrancher {
@Test fun testOne() {
// when NOT null or empty
emptyList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").whenNotNullNorEmpty { list ->
assertEquals(listOf("a", "b"), list)
}.otherwise {
fail("should not branch here")
}
// when YES null or empty
emptyList<String>().whenNullOrEmpty {
// sucess
}.otherwise { list ->
fail("should not branch here")
}
nullList<String>().whenNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").whenNullOrEmpty {
fail("should not branch here")
}.otherwise { list ->
assertEquals(listOf("a", "b"), list)
}
// with NOT null or empty
emptyList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").withNotNullNorEmpty {
assertEquals(listOf("a", "b"), this)
}.otherwise {
fail("should not branch here")
}
// with YES null or empty
emptyList<String>().withNullOrEmpty {
// sucess
}.otherwise {
fail("should not branch here")
}
nullList<String>().withNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").withNullOrEmpty {
fail("should not branch here")
}.otherwise {
assertEquals(listOf("a", "b"), this)
}
}
fun <T : Any> nullList(): List<T>? = null
}
答案 1 :(得分:26)
<强>更新强>
kotlin 1.3现在提供isNullOrEmpty
!
https://twitter.com/kotlin/status/1050426794682306562
试试这个!很清楚。var array: List<String>? = null
if (array.orEmpty().isEmpty()) {
// empty
} else {
// not empty
}
答案 2 :(得分:5)
除了其他答案之外,您还可以将安全呼叫运算符与扩展方法isNotEmpty()
结合使用。由于安全调用,返回值实际为Boolean?
,可以是true
,false
或null
。要在if
或when
子句中使用该表达式,您需要明确检查它是否为true
:
when {
activities?.isNotEmpty() == true -> doSomething
else -> doSomethingElse
}
使用elvis运算符的替代语法:
when {
activities?.isNotEmpty() ?: false -> doSomething
else -> doSomethingElse
}
答案 3 :(得分:5)
更简单的方法是,
if(activities?.isNotEmpty() == true) doSomething() else doSomethingElse()
答案 4 :(得分:2)
如果合适,请考虑使用?.forEach
activities?.forEach {
doSmth(it)
}
如果你想要你所描述的行为,我认为你的变体读起来比我能想到的更简洁。 (然而简单的if
就足够了)
答案 5 :(得分:0)
在我的情况下,price是可选的。我用orEmpty()
来处理情况,它返回给定数组或如果给定数组为null则返回一个空数组。
val safeArray = poi.prices.orEmpty()
if (!safeArray.isEmpty()) {
...
}
答案 6 :(得分:0)
在Kotlin 1.3中使用的实际方法是isNullOrEmpty
,就像在此答案中提到的:https://stackoverflow.com/a/48056456/2735286
以下是其用法示例:
fun main(args: Array<String>) {
var array: MutableList<String>? = null
println(array.isNullOrEmpty()) // true
array = mutableListOf()
println(array.isNullOrEmpty()) // true
array = mutableListOf("a")
println(array.isNullOrEmpty()) // false
}
此示例打印出来:
true
true
false
答案 7 :(得分:0)
Kotlin 1.3的扩展名为isNullOrEmpty。简短的答案是:
if (activities.isNullOrEmpty) doSomething
else doSomethingElse
扩展名定义为:
fun <T> Collection<T>?.isNullOrEmpty(): Boolean
String和Array存在类似的扩展名。
答案 8 :(得分:-1)
首先,我想建议除了@ mlatu的答案之外还要进行扩展功能,它处理else
条件
public inline fun Map.forEachElse(operation: (Map.Entry) -> Unit, elseBlock: () -> Unit): Unit {
if (!empty)
for (element in this) operation(element)
else
elseBlock()
}
但用法并不那么美好。
其实你正在寻找一个可能的monad