根据条件在 Kotlin 中创建列表

Creating a List in Kotlin based on Conditions

此刻我的乐趣是:

private fun validateArguments(city: String, state: String, country: String, zip: String): List<String> {

        val list: MutableList<String> = mutableListOf()
        if (city.isNullOrBlank()) list.add("Invalid city")
        if (state.isNullOrBlank()) list.add("Invalid state")
        if (country.isNullOrBlank()) list.add("Invalid country")
        if (zip.isNullOrBlank()) list.add("Invalid zip code")

        return list.toList()
}

我想知道是否有更优雅的方法来创建列表。 我猜最后的列表也可能是一个 MutableList。

我不确定是否有明显更好的方法;已经相当简洁明了了。

但这里有一个替代方案,使用 listOfNotNull and takeIf 函数来避免显式临时列表:

private fun validateArguments(city: String, state: String, country: String, zip: String)
    = listOfNotNull(
        "Invalid city".takeIf{ city.isNullOrBlank() },
        "Invalid state".takeIf{ state.isNullOrBlank() },
        "Invalid country".takeIf{ country.isNullOrBlank() },
        "Invalid zip code".takeIf{ zip.isNullOrBlank() })

此处takeIf() returns不满足条件则为null;然后 listOfNotNull() 删除所有这些空值,只留下满足的错误。

如果您使用的是 Kotlin 1.6+,则有用于列表、集合和映射的构建器 API:

val list = buildList {
    if (city.isNullOrBlank()) add("Invalid city")
    if (state.isNullOrBlank()) add("Invalid state")
    if (country.isNullOrBlank()) add("Invalid country")
    if (zip.isNullOrBlank()) add("Invalid zip code")
}

这允许将可变句柄的范围限制在列表中,并且只公开只读接口。它也非常适合提取的方法。

如果没有一些疯狂的解决方案(例如反射),你不能做太多的事情来缩短它。如果所有参数总是字符串并且错误消息总是非常相似,您可以删除一些冗余代码:

@OptIn(ExperimentalStdlibApi::class)
private fun validateArguments2(city: String, state: String, country: String, zip: String) = buildList {
    for ((value, name) in listOf(
        city to "city",
        state to "state",
        country to "country",
        zip to "zip code"
    )) {
        if (value.isBlank()) {
            add("Invalid $name")
        }
    }
}

但是如果你没有大量的这些参数,它就没有太大意义。

此外,如果您的参数甚至不可为空,则您无需检查空值 (isNullOrBlank())。

更新

或没有实验性 API:

private fun validateArguments2(city: String, state: String, country: String, zip: String) : List<String> {
    return listOf(
        city to "city",
        state to "state",
        country to "country",
        zip to "zip code"
    ).filter { it.first.isBlank() }
        .map { "Invalid ${it.second}" }
}

但是对于 reader 来说,它会比你最初的实现更加神秘,所以你真的需要有一个这样做的理由。