我有一个可为空的属性(一个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)
}
}
但对于如此简单的操作来说,仍然感觉工作量太大。我有一种感觉,结合let
、when
和with
,我可以把它瘦到更短一点。
步骤如下:
- 如果对象 (A) 不为空
- 如果对象 (A) 的字符串表示形式 (B) 不为空
- 对 (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 使用可为空的值,而其他函数则不然。 您可以根据需要以任何方式设计这些内容。 这取决于你!
有关此主题的详细信息,请参阅: 处理可为空值的惯用方法