Strings #
The Kotlin Standard Library provides hundreds of functions for working with String — far richer than what Java offers. These functions are implemented as extension functions on the String and CharSequence types, so you can call them directly like native methods. This article is a comprehensive reference to all the String functions available in the Kotlin Standard Library, grouped by usefulness, complete with practical examples.
Creating Strings #
// A regular literal
val biasa = "Hello, Kotlin!"
// Raw string (multiline, no escaping needed)
val multiline = """
First line
Second line
Third line
""".trimIndent()
// String templates
val nama = "Budi"
val umur = 28
val sapaan = "Name: $nama, Age: $umur years, Name length: ${nama.length}"
// Char to String
val karakter = 'K'
val dariChar = karakter.toString() // "K"
val dariCode = 75.toChar().toString() // "K" (ASCII code)
// String from collections
val daftar = listOf("Kotlin", "Java", "Python")
val digabung = daftar.joinToString(", ") // "Kotlin, Java, Python"
val dgnPrefix = daftar.joinToString(", ", "[", "]") // "[Kotlin, Java, Python]"
val dgnTransform = daftar.joinToString { it.uppercase() } // "KOTLIN, JAVA, PYTHON"
// String.format — printf-style formatting
val format1 = "Name: %s, Age: %d" .format("Budi", 28) // "Name: Budi, Age: 28"
val format2 = "Price: Rp%,.0f".format(15_000_000.0) // "Price: Rp15,000,000"
val format3 = "%05d".format(42) // "00042"
val format4 = "%.2f".format(3.14159) // "3.14"
// buildString — a builder DSL
val dibangun = buildString {
append("Hello, ")
append("Kotlin")
appendLine("!") // append + newline
append("Version: ")
append(2)
repeat(3) { append(".") }
}
Inspection and Validation #
val teks = " Hello, Kotlin! "
val kosong = ""
val spasiSaja = " "
// Check length and emptiness
println(teks.length) // 18
println(teks.isEmpty()) // false — only checks length == 0
println(kosong.isEmpty()) // true
println(spasiSaja.isEmpty()) // false — there are characters (spaces)
println(spasiSaja.isBlank()) // true — all whitespace
println(teks.isBlank()) // false
println(teks.isNotEmpty()) // true
println(teks.isNotBlank()) // true
// Check prefixes and suffixes
val url = "https://kotlin.unisbadri.com/api/v1"
println(url.startsWith("https://")) // true
println(url.endsWith("/v1")) // true
println(url.startsWith("http://")) // false
println(url.contains("unisbadri")) // true
println(url.contains("kotlin", ignoreCase = true)) // true
// Check characters
println("12345".all { it.isDigit() }) // true — all digits
println("Hello".all { it.isLetter() }) // true — all letters
println("Kotlin123".any { it.isDigit() }) // true — has a digit
println("abc".none { it.isUpperCase() }) // true — no uppercase letters
// Simple format validation
val email = "[email protected]"
val isEmail = email.contains("@") && email.contains(".")
println(isEmail) // true (simple validation, use Regex for more accuracy)
// Check first and last characters
println("Kotlin".first()) // K
println("Kotlin".last()) // n
println("Kotlin".firstOrNull()) // K
println("".firstOrNull()) // null (safe, doesn't throw)
Comparison #
val a = "Kotlin"
val b = "kotlin"
val c = "Kotlin"
// Case-sensitive comparison (default)
println(a == b) // false
println(a == c) // true
println(a.equals(b)) // false
// Case-insensitive comparison
println(a.equals(b, ignoreCase = true)) // true
println(a.equals(b, ignoreCase = false)) // false
println(a.compareTo(b, ignoreCase = true)) // 0 (equal)
// Lexicographic comparison
println("apple".compareTo("banana")) // negative (apple < banana)
println("banana".compareTo("apple")) // positive (banana > apple)
println("apple".compareTo("apple")) // 0 (equal)
// Sorting with compareTo
val kata = listOf("banana", "Apple", "cherry", "Date")
println(kata.sortedWith(compareBy(String::lowercase)))
// [Apple, banana, cherry, Date] — case-insensitive sort
// Content equality vs reference
val s1 = "Hello"
val s2 = "Hello"
println(s1 == s2) // true — same content (structural equality)
println(s1 === s2) // true/false — reference (depends on JVM string interning)
Searching and Indexing #
val teks = "Kotlin is a great language. Kotlin is very powerful."
// indexOf — the first occurrence position
println(teks.indexOf("Kotlin")) // 0
println(teks.indexOf("kotlin")) // -1 (case-sensitive)
println(teks.indexOf("kotlin", ignoreCase = true)) // 0
println(teks.indexOf("Kotlin", startIndex = 5)) // 33 (search from index 5)
println(teks.indexOf("doesn't exist")) // -1
// lastIndexOf — the last occurrence position
println(teks.lastIndexOf("Kotlin")) // 33
println(teks.lastIndexOf("Kotlin", startIndex = 10)) // 0 (search from the right, starting at 10)
// indexOfFirst and indexOfLast — with a lambda condition
println(teks.indexOfFirst { it.isUpperCase() }) // 0 (K)
println(teks.indexOfLast { it == '.' }) // 51
// Check existence
println("Kotlin" in teks) // true — the in operator
println(teks.contains("Kotlin")) // true
// Find all occurrences using Regex
val semuaKotlin = Regex("Kotlin").findAll(teks)
semuaKotlin.forEach { match ->
println("Found '${match.value}' at index ${match.range.first}")
}
// Found 'Kotlin' at index 0
// Found 'Kotlin' at index 33
Transformation #
Capitalization and Case #
val teks = "halo, kotlin programming!"
// Change case
println(teks.uppercase()) // HALO, KOTLIN PROGRAMMING!
println(teks.lowercase()) // halo, kotlin programming!
println(teks.replaceFirstChar { it.uppercase() }) // Halo, kotlin programming!
println("HALO".replaceFirstChar { it.lowercase() }) // hALO
// capitalize (deprecated since Kotlin 1.5, use replaceFirstChar)
// println(teks.capitalize()) // deprecated
// Title case — every word starts with an uppercase letter
fun String.toTitleCase(): String {
return split(" ").joinToString(" ") { word ->
word.replaceFirstChar { it.uppercase() }
}
}
println("kotlin is a cool language".toTitleCase()) // Kotlin Is A Cool Language
// Per-character upper/lowercase
println("Kotlin".map { if (it.isLetter()) it.uppercaseChar() else it }.joinToString(""))
// KOTLIN
Removing Whitespace #
val teks = " \t Kotlin \n "
println(teks.trim()) // "Kotlin" — remove whitespace from both ends
println(teks.trimStart()) // "Kotlin \n " — remove only from the start
println(teks.trimEnd()) // " \t Kotlin" — remove only from the end
// Trim specific characters
println("---Kotlin---".trim('-')) // "Kotlin"
println("xxxKotlinxxx".trimStart('x')) // "Kotlinxxx"
println("xxxKotlinxxx".trimEnd('x')) // "xxxKotlin"
// Trim with a lambda condition
println(" 123Kotlin456 ".trim { !it.isLetter() }) // "Kotlin"
Replace and Substitution #
val teks = "Hello, Kotlin! Kotlin is great!"
// replace — replace all occurrences (literal)
println(teks.replace("Kotlin", "Java")) // "Hello, Java! Java is great!"
println(teks.replace("kotlin", "Java", ignoreCase = true)) // same, case-insensitive
// replaceFirst — only replace the first occurrence
println(teks.replaceFirst("Kotlin", "Python")) // "Hello, Python! Kotlin is great!"
// replace with a lambda — transform every match
println(teks.replace(Regex("[A-Z]")) { "[${it.value}]" })
// "[H]ello, [K]otlin! [K]otlin is great!"
// replaceRange — replace a specific section
println("Hello, World!".replaceRange(6, 11, "Kotlin")) // "Hello, Kotlin!"
// Remove substrings
println("Hello, Kotlin!".removePrefix("Hello, ")) // "Kotlin!"
println("Hello, Kotlin!".removeSuffix("!")) // "Hello, Kotlin"
println("Hello, Kotlin!".removePrefix("Wrong")) // "Hello, Kotlin!" (unchanged)
println("---Kotlin---".removeSurrounding("---")) // "Kotlin"
Splitting and Taking Substrings #
val csv = "Budi,28,Jakarta,Programmer"
// split — break by delimiter
val kolom = csv.split(",")
println(kolom) // [Budi, 28, Jakarta, Programmer]
println(kolom.size) // 4
// split with a limit
val duaBagian = csv.split(",", limit = 2)
println(duaBagian) // [Budi, 28,Jakarta,Programmer]
// split with Regex
val kalimat = "Kotlin; Java, Python\tGo"
val kata = kalimat.split(Regex("[;,\\s]+"))
println(kata) // [Kotlin, Java, Python, Go]
// lines — break by newlines
val multiline = "Line 1\nLine 2\nLine 3"
println(multiline.lines()) // [Line 1, Line 2, Line 3]
println(multiline.lineSequence().count()) // 3
// Taking substrings
val teks = "Kotlin Programming"
println(teks.substring(0, 6)) // "Kotlin" — indices 0 through 5
println(teks.substring(7)) // "Programming" — from index 7 to the end
println(teks.substring(0..5)) // "Kotlin" — with a range
// substringBefore and substringAfter
val url = "https://example.com/api/v1"
println(url.substringAfter("://")) // "example.com/api/v1"
println(url.substringBefore("/api")) // "https://example.com"
println(url.substringAfterLast("/")) // "v1"
println(url.substringBeforeLast("/")) // "https://example.com/api"
// take and drop
println("Kotlin".take(3)) // "Kot" — take N characters from the start
println("Kotlin".drop(3)) // "lin" — drop N characters from the start
println("Kotlin".takeLast(3)) // "lin" — take N characters from the end
println("Kotlin".dropLast(3)) // "Kot" — drop N characters from the end
// takeWhile and dropWhile
println("123abc".takeWhile { it.isDigit() }) // "123"
println("123abc".dropWhile { it.isDigit() }) // "abc"
Padding and Filling #
// padStart — add characters at the start
println("42".padStart(5)) // " 42" — default spaces
println("42".padStart(5, '0')) // "00042" — pad with '0'
println("Kotlin".padStart(3)) // "Kotlin" — unchanged if already long enough
// padEnd — add characters at the end
println("Kotlin".padEnd(10)) // "Kotlin "
println("Kotlin".padEnd(10, '-')) // "Kotlin----"
// Example usage: a table with aligned columns
val daftar = listOf("Budi", "Sari", "Ahmad Fauzi")
daftar.forEach { nama ->
print(nama.padEnd(15))
println("(${nama.length} characters)")
}
// Budi (4 characters)
// Sari (4 characters)
// Ahmad Fauzi (11 characters)
Type Conversion #
// String to numbers
println("42".toInt()) // 42
println("3.14".toDouble()) // 3.14
println("42".toLong()) // 42L
println("true".toBoolean()) // true
println("false".toBoolean()) // false
println("not a boolean".toBoolean()) // false (doesn't throw!)
// Safe conversion (returns null on failure)
println("42".toIntOrNull()) // 42
println("abc".toIntOrNull()) // null
println("3.14".toDoubleOrNull()) // 3.14
println("".toIntOrNull()) // null
// With a default value using Elvis
val angka = "abc".toIntOrNull() ?: 0
println(angka) // 0
// String to Char array and ByteArray
val chars = "Kotlin".toCharArray()
println(chars.toList()) // [K, o, t, l, i, n]
val bytes = "Kotlin".toByteArray()
println(bytes.size) // 6
val kembali = bytes.toString(Charsets.UTF_8)
println(kembali) // "Kotlin"
// Base64 encoding/decoding
val encoded = java.util.Base64.getEncoder().encodeToString("Kotlin".toByteArray())
println(encoded) // "S290bGlu"
val decoded = String(java.util.Base64.getDecoder().decode(encoded))
println(decoded) // "Kotlin"
Iteration and Character Processing #
val teks = "Kotlin 2024"
// Character iteration
for (c in teks) print("$c-") // K-o-t-l-i-n- -2-0-2-4-
// forEachIndexed
teks.forEachIndexed { i, c ->
if (c.isDigit()) println("Digit '$c' at index $i")
}
// map — transform every character
val hurufBesar = teks.map { it.uppercaseChar() }.joinToString("")
println(hurufBesar) // KOTLIN 2024
// filter — filter characters
val hurufSaja = teks.filter { it.isLetter() }
println(hurufSaja) // Kotlin
val digitSaja = teks.filter { it.isDigit() }
println(digitSaja) // 2024
// count — count characters meeting a condition
println(teks.count { it.isUpperCase() }) // 1 (K)
println(teks.count { it.isDigit() }) // 4
// Partition characters
val (huruf, bukan) = teks.partition { it.isLetter() }
println(huruf) // Kotlin
println(bukan) // " 2024"
// any and all on characters
println(teks.any { it.isDigit() }) // true
println(teks.all { it.isLetter() }) // false (there are spaces and digits)
StringBuilder — Efficiency for Concatenation #
// ANTI-PATTERN: repeated concatenation in a loop
var hasil = ""
for (i in 1..1000) {
hasil += "item-$i," // Creates a new String object every iteration — inefficient
}
// CORRECT: StringBuilder
val sb = StringBuilder()
for (i in 1..1000) {
sb.append("item-$i")
if (i < 1000) sb.append(",")
}
val hasilFinal = sb.toString()
// Or more idiomatically with buildString
val hasilIdiomatis = buildString {
for (i in 1..1000) {
append("item-$i")
if (i < 1000) append(",")
}
}
// Other StringBuilder operations
val sb2 = StringBuilder("Kotlin")
sb2.insert(0, "Hello, ") // insert at the start
sb2.append(" 2024") // append at the end
sb2.delete(0, 7) // delete "Hello, "
sb2.reverse() // reverse the order
sb2.replace(0, 6, "Java") // replace a range
println(sb2.toString())
// StringBuilder as a mutable String view
val sb3 = StringBuilder("Kotlin Programming")
sb3[0] = 'k' // StringBuilder can be modified via indices
println(sb3) // kotlin Programming
Useful Custom Extension Functions #
// Convert to a URL slug
fun String.toSlug(): String {
return this
.lowercase()
.replace(Regex("[^a-z0-9\\s-]"), "")
.replace(Regex("\\s+"), "-")
.trim('-')
}
println("Learn Kotlin 2024!".toSlug()) // "learn-kotlin-2024"
// Truncate with an ellipsis
fun String.truncate(panjang: Int, ellipsis: String = "..."): String {
return if (length <= panjang) this
else "${substring(0, panjang - ellipsis.length)}$ellipsis"
}
println("Kotlin is a very powerful language".truncate(20))
// "Kotlin is a very ..."
// Check whether a string is a number
fun String.isNumeric(): Boolean = toDoubleOrNull() != null
println("3.14".isNumeric()) // true
println("abc".isNumeric()) // false
println("42".isNumeric()) // true
// Mask sensitive strings
fun String.maskAkhir(tampilkan: Int = 4, maskChar: Char = '*'): String {
if (length <= tampilkan) return this
return "${maskChar.toString().repeat(length - tampilkan)}${takeLast(tampilkan)}"
}
println("4111111111111234".maskAkhir(4)) // "************1234"
println("[email protected]".maskAkhir(7)) // "......email.com"
// Count words
fun String.jumlahKata(): Int = trim().split(Regex("\\s+")).filter { it.isNotEmpty() }.size
println("Kotlin is a cool language".jumlahKata()) // 5
// Convert camelCase to snake_case
fun String.toSnakeCase(): String {
return replace(Regex("([a-z])([A-Z])"), "$1_$2").lowercase()
}
println("namaLengkapPengguna".toSnakeCase()) // "nama_lengkap_pengguna"
// Convert snake_case to camelCase
fun String.toCamelCase(): String {
return split("_").mapIndexed { i, word ->
if (i == 0) word.lowercase() else word.replaceFirstChar { it.uppercase() }
}.joinToString("")
}
println("nama_lengkap_pengguna".toCamelCase()) // "namaLengkapPengguna"
Summary #
isBlank()vsisEmpty()—isEmpty()only checks length == 0;isBlank()also treats strings containing only whitespace as “empty”. For user input validation,isBlank()is almost always more appropriate.toIntOrNull()is safer thantoInt()—toInt()throwsNumberFormatExceptionif the string isn’t a number.toIntOrNull()returns null which can be handled with the Elvis operator?: 0.substringAfter()andsubstringBefore()— very useful for parsing URLs, file paths, and structured text formats. Cleaner thansplit()[1]which is prone toIndexOutOfBoundsException.buildString { }for complex concatenation — usebuildStringinstead of+concatenation in loops. It usesStringBuilderbehind the scenes without boilerplate.joinToString()for collections — more expressive than manual loops. Supports prefix, postfix, separator, and per-element transformation in a single call.filter { }andmap { }on Strings — a String can be processed like a character collection."Kotlin".filter { it.isLetter() }returns a new String containing only letters.padStart()andpadEnd()— useful for table output formatting, numbers with leading zeros (padStart(5, '0')), and text alignment.- Extension functions for domain logic — create extension functions specific to your needs:
toSlug(),maskAkhir(),toSnakeCase(). This makes code more expressive and reusable.