Идиома Котлина для работы с ненулевым объектом и непустым строковым представлением

у меня есть свойство nullable (объект Java), которое знает, как преобразовать себя в строку, и если это представление не пустое, я хотел бы что-то с ним сделать. В Java это выглядит так:

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

Я пытаюсь найти самый идиоматический способ преобразования этого в Котлин, и у меня есть:

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

но все равно кажется, что слишком много работы для такой простой операции. У меня такое чувство, что объединение let, when и with Я могу уменьшить это к чему-то более короткому.

действия:

  1. если объект (A) не равен null
  2. если строковое представление (B) объекта (A) не является пустым
  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, который я действительно не хочу включать.

что "Котлин Уэй" здесь?

1 ответов


вы можете использовать (начиная с Kotlin 1.1) встроенный stdlib takeIf() или 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) }

, который определяется как расширение к нам!--13-->:

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 безопасный accessor и другие времена нет. Это связано с тем, что predicat/lambdas некоторых функций работают с нулевыми значениями, А другие-нет. Вы можете спроектировать их так, как хотите. Это до вас!

для получения дополнительной информации по этой теме см.: идиоматический способ борьбы с nullables