What a string is
A string is a sequence of characters: a word, a sentence, a number written as text, or even nothing at all. In Kotlin the type is String, and a string literal is written between double quotes.
val greeting = "Hello"
val empty = ""
val name = "Ada"
println("$greeting, $name!") // Hello, Ada!
The last line uses a string template. A $ followed by a variable name puts the variable's value into the text, and ${...} does the same for a whole expression, such as "${name.length} letters".
Single quotes mean something different. 'A' is a Char, exactly one character, while "A" is a String that happens to hold one character. The two types are not interchangeable, and Kotlin won't convert between them for you.
Characters and positions
Every character in a string has an index, and indexes start at 0. Square brackets read one character, and the length property says how many there are. It is a property, so there are no parentheses after it.
val str = "Hello"
println(str[0]) // H
println(str[str.length - 1]) // o
println(str.length) // 5
The last valid index is always length - 1. Asking for str[5] on this string throws a StringIndexOutOfBoundsException when the program runs.
A for loop can walk through the characters directly, or through the indexes when the position matters:
for (c in "Andy") print(c) // Andy
println()
for (i in "Andy".indices) print("$i ") // 0 1 2 3
Strings never change
A Kotlin String is immutable: once it exists, none of its characters can be replaced. Trying to assign to one is a compile error:
val myStr = "Bob"
myStr[0] = 'J' // error: no 'set' operator method providing array access.
Every operation that looks like a change actually builds a new string. "Hello".uppercase() returns "HELLO" and leaves the original alone. To "change" a string, you store the new one, which needs a var:
var word = "Bob"
word = "Job"
word += "s"
println(word) // Jobs
Keep two ideas apart here. val and var decide whether the variable can point to a different string. Immutability is about the string itself, and it holds either way.
Tools you will use constantly
| Expression | Result |
|---|---|
"Hello".substring(1, 3) | "el" (end index excluded) |
"Hello".substring(2) | "llo" |
"banana".indexOf("an") | 1 (-1 when absent) |
"banana".contains("nan") | true |
"banana".replace("a", "o") | "bonono" |
"a,b,c".split(",") | [a, b, c], a List<String> |
"ab".repeat(3) | "ababab" |
" hi ".trim() | "hi" |
Comparing strings
In Kotlin, == compares the contents of two strings, because it calls equals behind the scenes. Two strings built in different ways are equal when they hold the same characters. The operator === compares references, which is almost never what you want for strings. The ordering operators < and > compare strings character by character, so "abc" < "abd" is true. Upper-case letters sort before lower-case ones, and equals("X", ignoreCase = true) ignores case when you need that.
Building strings piece by piece
Joining strings with + or += creates a brand-new string each time and copies the old text into it. For a handful of joins that is fine. When a loop builds a long string, the repeated copying adds up, and a StringBuilder, which grows in place, is the better tool. The Strings chapter compares both approaches.
Why strings matter in this chapter
Most string problems come down to four moves: reading a character by index, looping over the characters, building a new string from pieces, and comparing two strings. The next lessons practise them: creating and joining strings, reversing a string, checking for palindromes and printing patterns of characters. Because strings are immutable, you will often copy the characters into a CharArray or a StringBuilder, change that, and turn it back into a String.
Key takeaways
- A
Stringuses double quotes; aCharuses single quotes. - Indexes start at 0,
lengthis a property, and the last index islength - 1. - Strings are immutable, and every change produces a new string.
==compares contents.- Templates such as
"$name"are the clean way to mix values into text.