Kotlin Help

Strings

The String type represents a sequence of characters. You can use it for text values, such as words, sentences, messages, or structured text.

The String type is immutable. After you create a String object, its contents stay the same for the rest of its lifetime. Any operation that appears to modify the string actually creates a new string.

Declare strings

To declare a String literal, enclose the value in double quotes (""). You can specify the String type explicitly or let Kotlin infer it from the value:

val name: String = "Kotlin" val message = "Hello, world!" // Kotlin infers String

Double-quoted string literals support escape sequences such as \n or \t:

val message = "Hello,\nworld!" val quote = "Kotlin says, \"Hi\"."

Multiline strings

To store text that consists of multiple lines or contains quotes that you don't want to escape, use a multiline string enclosed in triple quotes (""" """):

val text = """ Hello, Kotlin """ val quote = """Kotlin says, "Hi"."""

Multiline strings preserve line breaks and indentations as written in the source code. This behavior is useful when you want the runtime value to match the text layout in your file.

In the following example, the spaces before each line are part of the resulting string:

val text = """ Hello, Kotlin """

To remove common leading indentation, use the trimIndent() function. It detects the common minimal indent of non-empty lines and removes it:

fun main() { //sampleStart val text = """ Hello, Kotlin """.trimIndent() println(text) //sampleEnd }

To control indentation removal more explicitly, use the trimMargin() function. It removes everything before and including the margin prefix on each line:

fun main() { //sampleStart val text = """ |Hello, |Kotlin """.trimMargin() println(text) //sampleEnd }

By default, the trimMargin() function uses a pipe symbol (|) as the margin prefix, but you can pass another character as a parameter. For example: trimMargin(">").

String templates

String templates let you embed variables and expressions directly inside a String literal. This process is called interpolation. You can use string templates in both regular and multiline strings.

To insert a variable into a string, use the $ symbol:

fun main() { //sampleStart val name = "Kotlin" println("Hello, $name") // Hello, Kotlin //sampleEnd }

To insert an expression into a string or to place a variable directly next to other text, use ${}:

fun main() { //sampleStart val text = "abc" println("The length of $text is ${text.length}") // The length of abc is 3 val language = "Kotlin" println("${language}Lang") // KotlinLang //sampleEnd }

Template expressions can also contain double-quoted strings without escaping:

// Double-quoted string val test = "${"test".uppercase()}" // Multiline string val result = """ Result: ${"OK".lowercase()} """

Nullable values in string templates

If an interpolated expression or variable evaluates to null, the Kotlin compiler inserts the text null into the resulting string. To replace null with another value, use the Elvis operator (?:):

fun main(){ //sampleStart val text: String? = null println("Hello, $text") // Hello, null println("Hello, ${text ?: "Kotlin"}") // Hello, Kotlin //sampleEnd }

Multi-dollar string interpolation

In regular string templates, a single dollar sign ($) starts interpolation. If you need to include literal dollar signs in a string, use multi-dollar string interpolation.

Multi-dollar string interpolation allows you to specify how many consecutive dollar signs are required to trigger interpolation. Dollar signs below that number are treated as literal characters.

For example, when you use $$ before a string literal, interpolation begins only with two consecutive dollar signs:

val KClass<*>.jsonSchema : String get() = $$""" { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://example.com/product.schema.json", "$dynamicAnchor": "meta", "title": "$${simpleName ?: qualifiedName ?: "unknown"}", "type": "object" } """

Basic string operations

Kotlin provides a range of operations for working with strings. This section introduces some of the most commonly used operations.

Get string length

To get the number of characters in a string, use the length property:

fun main (){ //sampleStart val language = "Kotlin" println(language.length) // 6 //sampleEnd }

Access characters

You can access an individual character in a string with the indexing operator ([]):

fun main (){ //sampleStart val language = "Kotlin" println(language[0]) // K println(language[5]) // n //sampleEnd }

You can also iterate over the characters in a string:

fun main(){ //sampleStart for (char in "Kotlin") { println(char) } //sampleEnd }

Extract parts of a string

To extract parts of a string, use one of the following functions:

  • substring() to return a new string with the selected part of the original text.

  • subSequence() to return a CharSequence with the selected part of the original text.

For example:

fun main() { //sampleStart val text = "Kotlin" println(text.substring(1)) // otlin println(text.substring(1, 5)) // otli println(text.subSequence(1, 5)) // otli //sampleEnd }

Since the String type is immutable, these functions don't modify the original string.

Compare strings

You can check whether two strings have the same content with the == operator:

fun main(){ //sampleStart println("kotlin" == "kotlin") // true println("kotlin" == "Kotlin") // false //sampleEnd }

You can also compare strings lexicographically (character by character) with the compareTo() function. It scans both strings until it finds the first differing pair of characters and returns:

  • 0 when the strings are equal.

  • A value less than 0 when the receiver is smaller than the argument.

  • A value greater than 0 when the receiver is greater than the argument.

fun main() { //sampleStart println("abc".compareTo("abd") < 0) // true println("abc".compareTo("ABC") > 0) // true // Pass true to ignore case differences println("abc".compareTo("ABC", ignoreCase = true) == 0) // true //sampleEnd }

Work with string content

If you want to change the content of a string, create a modified copy of it with functions like .trim(), .replace(), .uppercase(), and .lowercase():

fun main() { //sampleStart val text = " Hello, Kotlin " println(text.trim()) // Hello, Kotlin println(text.replace("Kotlin", "world")) // Hello, world println(text.uppercase()) // HELLO, KOTLIN println(text.lowercase()) // hello, kotlin //sampleEnd }

You can also inspect the string content with the contains(), startsWith(), and endsWith() functions:

fun main() { //sampleStart val domain = "kotlinlang.org" // Checks if the string contains "." println(domain.contains(".")) // true // Checks if the string starts with "kotlin" println(domain.startsWith("kotlin")) // true // Checks if the string ends with ".org" println(domain.endsWith(".org")) // true //sampleEnd }

Split strings

You can divide a string into parts around a delimiter with the split() function:

fun main() { //sampleStart val numbers = "one, two, three" println(numbers.split(", ")) // [one, two, three] //sampleEnd }

If you want to split a string into individual lines, use the lines() function:

fun main() { //sampleStart val numbers = "one\ntwo\nthree" println(numbers.lines()) // [one, two, three] //sampleEnd }

Build and format strings

When you concatenate strings with the + operator, Kotlin creates a new String object for each operation. However, this approach may not be beneficial in loops or when you assemble many pieces. To avoid such issues, you can use the buildString() function or StringBuilder. They collect all pieces in a single mutable buffer and produce only one string at the end.

Use the buildString() function when the logic that determines what to append is complex. For example, when you have multiple conditions that contribute a different fragment. With buildString(), you don't handle the buffer directly. The function creates a StringBuilder internally, runs your block, and returns the resulting string.

fun main() { //sampleStart val hasErrors = true val hasWarnings = true val isComplete = false // buildString creates an empty buffer val status = buildString { // Appends "Errors found" to the buffer if (hasErrors) append("Errors found") if (hasWarnings) { // The buffer is not empty, appends "; " if (isNotEmpty()) append("; ") // Appends "Warnings found" append("Warnings found") } // isComplete = false, nothing to append if (isComplete) { if (isNotEmpty()) append("; ") append("Completed") } // The buffer is not empty, skips the fallback if (isEmpty()) append("OK") } println(status) // Errors found; Warnings found //sampleEnd }

Use StringBuilder when you need the buffer as an explicit value. For example, to change the existing text:

fun main() { //sampleStart val text = "Hello, Kotlin" val builder = StringBuilder(text) builder.replace(7, 13, "world") println(builder.toString()) // Hello, world //sampleEnd }

On the JVM, you can also format a string with the String.format() function:

val text = String.format("Hello, %s", "Kotlin")

String conversion

Often you may use strings to represent values of other types, such as numbers, Boolean values, or identifiers from the input. Kotlin provides functions for converting values to strings and for parsing strings into other types.

To return a string representation of a value, use the toString() function:

val number = 10 val text = number.toString()

In string templates and string concatenation, Kotlin converts values to strings automatically.

To convert a string to another type, use the corresponding parsing functions:

These functions return a value of the requested type if the string has a valid format. If the input may be invalid, use the OrNull variants. These functions return null instead of throwing an exception making them safe for user input or data that you don't fully control:

val toInt = "10".toInt() // 10 // 1000000000000 exceeds maximum value of Int val toIntInvalid = "1000000000000".toIntOrNull() val toBoolean = "true".toBooleanStrict() // true val toBooleanInvalid = "yes".toBooleanStrictOrNull() // null
29 June 2026