Ion Kotlin for working with non-zero object and non-empty string representation

I have a nullable property (Java object) that knows how to convert itself to String, and if this view is not empty, I would like to do something with it. In Java, it looks like this:

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

I am trying to find the most idiomatic way to convert this to Kotlin, and I have:

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

But there is still too much work for such a simple operation. I have a feeling that combining let , when and with I can reduce this a little less.

Steps:

  • If object (A) is not null
  • If the string representation (B) of the object (A) is not empty.
  • Do something with (B)

I tried:

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

But (1) it fails:

 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 

And even if it passes, (2) he will want a comprehensive else , which I really don't want to include.

What is the "Kotlin path" here?

+8
tostring nullable condition kotlin
source share
1 answer

You can use the built-in stdlib (starting with Kotlin 1.1) takeIf() or takeUnless either work:

 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) 

To perform the doSomethingWith() action on the final value, you can use apply() to work in the context of the current object and return is the same object, or let() to change the result of the expression, or run() to work in the context of the current object , as well as change the result of the expression or also() execute the code when the original object is returned.

You can also create your own extension function if you want the naming to be more meaningful, for example nullIfBlank() might be a good name:

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

which is defined as an extension to a nullable String :

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

If we add another extension:

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

This simplifies the code:

 obj?.toString()?.whenNotNullOrBlank { doSomethingWith(it) } // or with a function reference obj?.toString()?.whenNotNullOrBlank(::doSomethingWith) 

You can always write extensions like this to improve the readability of your code.

Note. Sometimes I used a safe accessor ?. null and the other not. This is because the / lambdas predicate of some functions works with NULL values, while others do not. You can design them the way you want. This is for you!

For more information on this topic, see the Idiomatic Way to Solve Problems with nullables

+9
source share

All Articles