34

According to the official kotlin documentation, the toString() call of a null object returns "null" toString()

I want, that toString() should return an empty string ("") instead. I implemented it with an extension function.

fun Any?.toEmptyStringIfNull() :String {
if (this == null) {
    return ""
} else {
    return toString()
}

I am wondering if this could be achieved simpler/easier/cleaner and without calling the extension function everytime.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Lukas Lechner
  • 7,881
  • 7
  • 40
  • 53

5 Answers5

55

How about:

nullable?.toString() ?: ""

or as Alexander Udalov suggested:

nullable?.toString().orEmpty()

Which one can wrap in an extension method:

fun Any?.toStringOrEmpty() = this?.toString() ?: ""
Community
  • 1
  • 1
miensol
  • 39,733
  • 7
  • 116
  • 112
15

you can directly use nullable.orEmpty().

Reference: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/or-empty.html

Edit: Answer provided is incomplete - does only apply for String? and not Any? as pointed out in comment below.

Hartmut
  • 725
  • 9
  • 11
1
nullable?.let {it.toString()}

If "nullable" is null it won't go further. As a variant. The only problem is that there will be a warning "redundant 'let' call could be removed.

0

I propose an extension function stringify, the name of which I borrowed from JavaScript's JSON.stringify().

fun <T> T?.stringify(toString: (T) -> String = { it.toString() }): String =
    if (this == null) "" else toString(this)

This covers the simple case and cases where you want to further process the string:

fun simplyConcatenate(s: String, postfix: String?): String = 
    s + postfix.stringify()

fun getFullTitle(title: String, disambiguation: String?): String = 
    title + disambiguation.stringify { " ($it)" }

fun demo() {
    println(simplyConcatenate("a", null)) // "a"
    println(simplyConcatenate("a", "b")) // "ab"
    println(getFullTitle("a", null)) // "a"
    println(getFullTitle("a", "b")) // "a (b)"
}

Edit: Now available in kotlin-lib.

Marco Eckstein
  • 4,448
  • 4
  • 37
  • 48
0

The above answer not work for variable that is not original as String? because the toString() will directly transform a Any? to String (not to String?) if you write something like xxx.toString() ?: "" or xxx.toString().orEmpty() the IDE will tell you the right path will never be reach.

The solution is use "let" or "run". Depend on do you need to access outer scope class’ fun.

    Any? let { it.toString() } ?: ""
    Any? run { toString() } ?: ""

For example a fun we want a file name string from a nullable Path, or even a non-null path, its getFileName() may return null. And we want a empty string in that case instead of a "null" string.

    fun fileName(path: Path?): String = path?.fileName?.run { toString() } ?: ""

    fun removeExtension(path: Path?): String = path?.fileName?.let { removeExtension(it.toString()) } ?: ""
    fun removeExtension(fileName: String): String = FilenameUtils.removeExtension(fileName)

Eric Chan
  • 49
  • 3