Strings & Templates

Kotlin · Lesson 6 of 29 6 min read Updated

Text is everywhere in programs: names, addresses, messages, receipts, search boxes. In Kotlin, text is stored in the String type. Kotlin makes strings pleasant to work with: you can drop values straight into text with templates, and the standard library has a function for almost every common job.

In this lesson you will build strings with templates, use the most important string functions, write multi-line text with raw strings, and learn the newer multi-dollar syntax for text that contains many $ signs.

String templates

A string template puts a value inside a string. Write $name for a simple variable, and ${...} for anything more: a calculation, a function call or a property.

Kotlin
fun main() {
    val name = "Farhan"
    val items = 3
    val pricePerItem = 249

    println("Hello, $name!")
    println("$name bought $items items for Rs ${items * pricePerItem}.")
    println("The name has ${name.length} letters")
    println("First letter: ${name[0]}, last letter: ${name.last()}")
}
Output
Hello, Farhan!
Farhan bought 3 items for Rs 747.
The name has 6 letters
First letter: F, last letter: n

A few things to notice:

  • name.length is the number of characters.
  • name[0] gets a single character by its index (position). Indexes start at 0, so the last index is length - 1.
  • name.last() gets the last character without you working out the index.

You can also join strings with +, as in "Hello, " + name, but templates are easier to read, and Kotlin developers prefer them.

Common string functions

Strings in Kotlin are immutable: no function changes the original string. Each function returns a new string, so you store or print the result.

Kotlin
fun main() {
    val raw = "  Kabir Singh  "
    val name = raw.trim()

    println("[$name]")
    println(name.uppercase())
    println(name.lowercase())
    println(name.startsWith("Kab"))
    println(name.contains("singh"))
    println(name.contains("singh", ignoreCase = true))
    println(name.indexOf("S"))
    println(name.substring(0, 5))
    println(name.replace("Singh", "Sharma"))
    println(name.split(" "))
}
Output
[Kabir Singh]
KABIR SINGH
kabir singh
true
false
true
6
Kabir
Kabir Sharma
[Kabir, Singh]
  • trim() removes spaces from both ends, very useful for user input.
  • contains, startsWith and endsWith answer yes or no questions. Many functions accept ignoreCase = true.
  • indexOf returns the position of the first match, or -1 if there is none.
  • substring(0, 5) takes characters from index 0 up to, but not including, index 5.
  • split(" ") breaks the text into a list of pieces.

Other everyday functions include isEmpty(), isBlank() (empty or only spaces), take(3) (first three characters), drop(3) (all but the first three) and lines() (split into lines).

Padding, repeating and reversing

When you print tables or receipts in a console, you want columns to line up. padEnd adds spaces on the right until the string reaches a length, and padStart adds them on the left.

Kotlin
fun main() {
    println("=".repeat(20))
    println("Tea".padEnd(12) + "15".padStart(8))
    println("Samosa".padEnd(12) + "20".padStart(8))
    println("Jalebi".padEnd(12) + "60".padStart(8))
    println("=".repeat(20))

    println("7".padStart(3, '0'))
    println("level".reversed())
}
Output
====================
Tea               15
Samosa            20
Jalebi            60
====================
007
level

padStart(3, '0') pads with zeros instead of spaces, which is handy for roll numbers and order IDs. "level".reversed() is still "level", because it is a palindrome.

Comparing strings and working with characters

Use == to compare the contents of two strings. For a case-insensitive check, use equals(other, ignoreCase = true). The < and > operators compare strings in dictionary order (by character codes, so all capital letters come before lowercase ones).

Kotlin
fun main() {
    println("Pune".equals("PUNE", ignoreCase = true))
    println("apple" < "banana")

    val pin = "1100a1"
    println(pin.length == 6 && pin.all { it.isDigit() })

    println("rohtak".replaceFirstChar { it.uppercase() })

    val code = buildString {
        append("EC")
        append('-')
        append(2026)
    }
    println(code)
}
Output
true
true
false
Rohtak
EC-2026

pin.all { it.isDigit() } checks every character; the part in braces is a small function called a lambda, which you will study in Lambdas & Higher-Order Functions. buildString collects pieces efficiently, which is better than adding strings with + inside a long loop.

Raw strings and trimIndent

A raw string is written between triple quotes """. It can span many lines, and backslashes are not escape characters inside it, which makes Windows paths and regular expressions easier to write. Templates still work.

Kotlin
fun main() {
    val name = "Meera"
    val receipt = """
        Receipt for $name
        Item: Notebook x 4
        Total: Rs ${4 * 45}
    """.trimIndent()
    println(receipt)

    val path = """C:\Users\meera\notes.txt"""
    println(path)
}
Output
Receipt for Meera
Item: Notebook x 4
Total: Rs 180
C:\Users\meera\notes.txt

trimIndent() removes the shared indentation from every line and drops the blank first and last lines, so you can indent the text nicely inside your code.

Common mistakes

  • Expecting a function to change the string. name.uppercase() on its own line does nothing useful. Write val upper = name.uppercase().
  • Template stops too early. "$user.name" inserts user and then the text .name. Use "${user.name}" for properties.
  • Index out of range. name[10] on a six-letter name crashes with StringIndexOutOfBoundsException. Check length first, or use getOrNull(10), which returns null instead.
  • Comparing with different case. "Pune" == "pune" is false. Normalise with lowercase() or use ignoreCase = true.

Key points

  • $name and ${expression} put values inside strings; prefer templates over +.
  • Strings are immutable; functions such as trim(), uppercase() and replace() return new strings.
  • Indexes start at 0; substring(a, b) excludes index b.
  • padStart, padEnd and repeat help line up console output.
  • Raw strings use """ and work well with trimIndent().
  • Kotlin 2.2 added $$"..." strings, where a single $ is plain text.

Exercise

Write a program that takes the messy input " priya SHARMA , jaipur " and prints a clean profile line: Name: Priya Sharma | City: Jaipur | Initials: PS. Use split(","), trim(), lowercase() and replaceFirstChar. (Hint: split the name into first and last name with split(" ").)

Show solution
Kotlin
fun main() {
    val input = "  priya SHARMA , jaipur "
    val parts = input.split(",")
    val names = parts[0].trim().split(" ")

    val first = names[0].lowercase().replaceFirstChar { it.uppercase() }
    val last = names[1].lowercase().replaceFirstChar { it.uppercase() }
    val city = parts[1].trim().replaceFirstChar { it.uppercase() }
    val initials = "${first[0]}${last[0]}"

    println("Name: $first $last | City: $city | Initials: $initials")
}
Output
Name: Priya Sharma | City: Jaipur | Initials: PS

Lower-casing first and then capitalising the first letter fixes any mix of cases, such as SHARMA.

Quick Quiz

1. What does "Kotlin".substring(1, 4) return?

2. How do you insert the length of name into a string?

3. What does " hi ".trim() do to the original variable?

4. In a $$"""...""" string, what is $id?

Learn Kotlin with a mentor

Free lessons get you started. Our Programming & Software Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call