Getting the length
Every Kotlin string has a length property that holds the number of characters in it. It is a property, not a method, so you write it without parentheses:
var message = "Hello world"
println(message.length) // 11
message += "!"
println(message.length) // 12
The space counts as a character, so "Hello world" has 11. The empty string "" has length 0. Because strings are immutable, message += "!" builds a new, longer string and stores it in message. The length is read from whichever string the variable refers to at that moment.
One detail for later: length counts UTF-16 code units, not visible symbols. Plain letters, digits and spaces are one unit each, but an emoji such as the grinning face takes two, so "a😀b".length is 4. For the text in this lesson the two counts agree.
Reaching the end of a string
Indexes start at 0, so a string of length n has valid indexes 0 to n - 1. The last character is therefore at length - 1:
val message = "Hello world"
val length = message.length
println(message[length - 1]) // d
println(message[length - 2]) // l
In general, the nth character from the end is message[length - n]. Kotlin does not accept negative indexes such as message[-1]: they throw an exception, the same as any index outside the string.
Slicing from the end
The same arithmetic works with substring. To take the last n characters, start at length - n and run to the end:
val message = "Hello world"
val length = message.length
var lastChars = message.substring(length - 4)
println(lastChars) // orld
lastChars = message.substring(length - 7)
println(lastChars) // o world
The end index is excluded, so passing length as the second argument also means "to the end". These two calls give the same string:
message.substring(length - 4)
message.substring(length - 4, length)
The exercise
The lesson gives message = "I love pancakes" and asks for three things, each printed with println.
- The length.
message.lengthis 15. Count the letters and the two spaces to confirm. - The last character. The last index is 14, which is
message.length - 1. That character iss. - The last 5 characters. Start at
message.length - 5, which is 10, and stop at the end of the string. The result iscakes.
val message = "I love pancakes"
println(message.length)
println(message[message.length - 1])
println(message.substring(message.length - 5, message.length))
The program prints:
15
s
cakes
Writing message.length inside the brackets each time is fine for a small program. When you need the length more than once, put it in a val length = message.length as the earlier examples do.
Walking a string with its length
The length also tells a loop where to stop. The valid indexes are 0 up to, but not including, length, which is exactly what the range 0 until length produces:
val word = "kotlin"
for (i in 0 until word.length) {
println("$i: ${word[i]}")
}
This prints the pairs 0: k through 5: n. The range 0..word.length would be a bug: it includes the length itself, and the last pass would read one position past the end. Kotlin also offers word.indices, which is the same range written for you, and for (c in word) when you only need the characters.
Kotlin shortcuts
The standard library has helpers for the end of a string, so you do not always need the arithmetic:
val message = "I love pancakes"
println(message.last()) // s
println(message.takeLast(5)) // cakes
last() throws a NoSuchElementException on an empty string, while lastOrNull() returns null instead. takeLast(5) never throws, even on a string shorter than 5 characters: it returns whatever there is.
Common mistakes
- Using the length as the last index.
message[message.length]is one position past the end and throws aStringIndexOutOfBoundsException. The last character is atlength - 1. - Writing
length()with parentheses. In Kotlinlengthis a property, somessage.length()is a compile error. (Collections usesize, and strings uselength.) - Taking the last character of an empty string. With length 0,
length - 1is -1, which is not a valid index. CheckisNotEmpty()first when the string might be empty. - Asking
substring(length - n)for more than the string has. Ifnis larger than the length, the start index is negative and the call throws.
Key takeaways
text.lengthis the number of characters, spaces included.- The last valid index is
length - 1. - The nth character from the end is
text[length - n]. - The last n characters are
text.substring(length - n).