用于处理非空对象和非空字符串表示的 Kotlin 习惯用法

Kotlin idiom for working with non-null object and non-blank String representation

我有一个可为 null 的 属性(一个 Java 对象),它知道如何将自身转换为字符串,如果此表示不为空,我想用它做一些事情。在 Java 中看起来像:

MyObject obj = ...
if (obj != null) {
    String representation = obj.toString();
    if (!StringUtils.isBlank(representation)) {
        doSomethingWith(representation);
    }
}

我正在尝试找到将其转换为 Kotlin 的最惯用的方法,并且我有:

    with(obj?.toString()) {
        if (!isNullOrBlank()) {
            doSomethingWith(representation)
        }
    }

但是这么简单的操作还是感觉工作量太大了。我有这种感觉,结合 letwhenwith,我可以将其精简为更短的内容。

步骤是:

  1. 如果对象 (A) 不为空
  2. 如果对象 (A) 的字符串表示形式 (B) 不为空
  3. 用 (B) 做点什么

我试过了:

    when(where?.toString()) {
        isNullOrBlank() -> builder.append(this)
    }

但是 (1) 它失败了:

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: @InlineOnly public inline fun 
 CharSequence?.isNullOrBlank(): Boolean defined in kotlin.text @InlineOnly public inline fun CharSequence?.isNullOrBlank(): Boolean defined in 
 kotlin.text

即使它超过了那个,(2) 它也需要详尽无遗的 else,我真的不想包括在内。

这里的"Kotlin way"是什么?

您可以使用(自 Kotlin 1.1 起)内置的 stdlib takeIf() or takeUnless 扩展,两者都有效:

obj?.toString().takeUnless { it.isNullOrBlank() }?.let { doSomethingWith(it) }

// or

obj?.toString()?.takeIf { it.isNotBlank() }?.let { doSomethingWith(it) }

// or use a function reference

obj?.toString().takeUnless { it.isNullOrBlank() }?.let(::doSomethingWith)

为了对最终值执行操作doSomethingWith(),您可以使用apply() to work within the context of the current object and the return is the same object, or let() to change the result of the expression, or run() to work within the context of the current object and also change the result of the expression, or also()在返回原始对象的同时执行代码。

如果你想让命名更有意义,你也可以创建自己的扩展函数,例如nullIfBlank()可能是一个好名字:

obj?.toString().nullIfBlank()?.also { doSomethingWith(it) }

定义为可空 String:

的扩展
fun String?.nullIfBlank(): String? = if (isNullOrBlank()) null else this

如果我们再添加一个扩展:

fun <R> String.whenNotNullOrBlank(block: (String)->R): R? = this.nullIfBlank()?.let(block)

这样可以将代码简化为:

obj?.toString()?.whenNotNullOrBlank { doSomethingWith(it) }

// or with a function reference

obj?.toString()?.whenNotNullOrBlank(::doSomethingWith)

您可以随时编写这样的扩展来提高代码的可读性。

注意:有时我使用 ?. null 安全访问器,有时不使用。这是因为某些函数的 predicat/lambdas 适用于可为 null 的值,而其他函数则不然。您可以按照自己的方式设计这些。由你决定!

有关此主题的更多信息,请参阅: