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



我有一个可为空的属性(一个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 方式"是什么?

您可以使用(从 Kotlin 1.1 开始)内置的 stdlibtakeIf()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()在当前对象的上下文中工作并且返回的是同一对象,或者let()更改表达式的结果,或者run()在当前对象的上下文中工作并更改表达式的结果, 或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/lambda 使用可为空的值,而其他函数则不然。 您可以根据需要以任何方式设计这些内容。 这取决于你!

有关此主题的详细信息,请参阅: 处理可为空值的惯用方法

最新更新