45

I am new to Kotlin, and I am looking for help in rewriting the following code to be more elegant.

var s: String? = "abc"
if (s != null && s.isNotEmpty()) {
    // Do something
}

If I use the following code:

if (s?.isNotEmpty()) {

The compiler will complain that

Required: Boolean
Found: Boolean?

Thanks.

4
  • 1
    Could you please edit your title to better reflect your question? Having many questions called How to write this code in a Kotlin way? doesn't really make it easy to look up later. Commented Dec 15, 2016 at 11:34
  • @marstran Yes sure. Do you have any suggestions about the title? I cannot find a good way to explain my problem. Thanks. Commented Dec 15, 2016 at 12:35
  • Something like How to idiomatically test for non-null, non-empty strings in Kotlin? maybe? Basically something that describes the actual question. Commented Dec 15, 2016 at 12:38
  • Since Kotlin 1.3, isNullOrEmpty and orEmpty are available on collections, maps, and array of objects. Not just on CharSequence. (kotlinlang.org/docs/reference/whatsnew13.html) Commented Dec 22, 2019 at 18:46

5 Answers 5

60

You can use isNullOrEmpty or its friend isNullOrBlank like so:

if(!s.isNullOrEmpty()){
    // s is not empty
}

Both isNullOrEmpty and isNullOrBlank are extension methods on CharSequence? thus you can use them safely with null. Alternatively turn null into false like so:

if(s?.isNotEmpty() ?: false){
    // s is not empty
}

you can also do the following

if(s?.isNotEmpty() == true){ 
    // s is not empty
}
Sign up to request clarification or add additional context in comments.

8 Comments

I would add that if (s != null && s.isNotEmpty()) { ... } is idiomatic Kotlin for this scenario if you want to proceed to actually use s as non-null using smart cast.
The question is not silly at all. Another possible form would be if (s?.isNotEmpty() == true) {}
@mfulton26 note that s was declared as var in which case if (s != null && s.isNotEmpty()) will not compile nor will it result in smart cast.
@miensol I notice that I get a smart cast very well even for a var. As long as it’s a local variable, it cannot have changed in between. Has Kotlin gotten smarter about this in the meantime?
@miguel Why do you have to keep track of that? If it was a member the code would not compile on a nullable type. No confusion imo.
|
6

Although I like the answer by @miensol very much, my answer would be (and that is why I do not put it in a comment): if (s != null && s.isNotEmpty()) { … } actually is the idiomatic way in Kotlin. Only this way will you get a smart cast to String inside the block, while with the way in the accepted answer you will have to use s!! inside the block.

3 Comments

The suggestion by @Kirill Rakhman will also produce a smart cast: if (s?.isNotEmpty() == true) {}
That’s true. It’s a matter of personal preference here. When I see the suspicious == true part I immediately think that it could be removed, which it cannot in this case. You save 4 characters, but for me it’s less readable.
Note that my answer is outdated. !s.isNullOrEmpty() will perform a smart cast.
3

or create an extension method and use it as a safe call:

fun String?.emptyToNull(): String? {
    return if (this == null || this.isEmpty()) null else this
}

fun main(args: Array<String>) {
    val str1:String?=""
    val str2:String?=null
    val str3:String?="not empty & not null"

    println(str1.emptyToNull()?:"empty string")
    println(str2.emptyToNull()?:"null string")
    println(str3.emptyToNull()?:"will not print")
}

1 Comment

Isn't something similar offered in Kotlin lang?
3

Or you can create an Extension Function:

public inline fun String?.ifNotEmpty(crossinline block: (String) -> Unit): Unit {
    if (this != null && this.isNotEmpty()) {
        block(this)
    }
}

See it in action

I find this approach more readable in context of Jetpack Compose which is a UI Toolkit.

handles.twitter.ifNotEmpty {
    SocialMediaItem(handle = it, type = SocialMedia.TWITTER)
}

In this case the intention is to only display that block of UI if Twitter handle is not null, and is not an empty string.

3 Comments

This doesnt work with compose code unfortunately (@Composable invocations can only happen from the context of a @Composable function)
With some small changes it works. Probably been som updated to kotlin/compose: public inline fun String?.ifNotEmpty(block: (String) -> Unit) { if (!this.isNullOrEmpty()) { return block(this) } }
@Gober if you want this function to accept Composable functions inside, the signature should be changed to crossinline block: @Composable (String) -> Unit
0

Another extension option. I was looking for a way of validating a bunch of strings and then using them, and the nested blocks are a pain for reading in that aspect.

fun String?.notNullOrEmpty(illegalArgumentExceptionMsg: String): String {
    return if (this == null || this.isEmpty()) throw IllegalArgumentException(illegalArgumentExceptionMsg) else this
}

simple use

    val myNullOrEmptyString: String? = "bar"
    val myNotNullString = myNullOrEmptyString.notNullOrEmpty("myNullOrEmptyString should not be empty")

use

    val myNullOrEmptyString: String? = "bar"
    val myNotNullString: String = myNullOrEmptyString.notNullOrEmpty("myNullOrEmptyString should not be empty")

Test or uses

@Test
fun emptyNotNullExtension() {
    val msg = "foo"
    assertThatThrownBy {
        val emptyNotNullString: String = "".notNullOrEmpty(msg)
    }
        .isExactlyInstanceOf(IllegalArgumentException::class.java)
        .hasMessageContaining(msg)
    assertThatThrownBy {
        val emptyNotNullString: String = null.notNullOrEmpty(msg)
    }
        .isExactlyInstanceOf(IllegalArgumentException::class.java)
        .hasMessageContaining(msg)

    val myNullOrEmptyString: String? = "bar"
    val myNotNullString: String = myNullOrEmptyString.notNullOrEmpty("myNullOrEmptyString should not be empty")

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.