Kotlin: Capitalize first letter of a string
Video: Kotlin: Capitalize first letter of a string by Taught by Celeste AI - AI Coding Coach
Kotlin: Capitalize the First Letter of a String
replaceFirstChar { it.uppercase() }is the modern Kotlin idiom. The deprecatedcapitalize()and the manuals[0].uppercaseChar() + s.substring(1)both work, but the first is cleanest.
A small string-manipulation puzzle that demos how Kotlin's API surface evolves — the "obvious" function (capitalize()) was deprecated in 1.5, and Copilot's suggestions sometimes lag behind.
The Copilot prompt
// Capitalize the first letter of a string
fun capitalizeFirstLetter(input: String): String {
Copilot may suggest:
fun capitalizeFirstLetter(input: String): String {
if (input.isEmpty()) return input
return input[0].uppercaseChar() + input.substring(1)
}
fun main() {
val original = "kotlin"
println(capitalizeFirstLetter(original)) // "Kotlin"
}
Walkthrough
Three pieces.
1. Empty guard. if (input.isEmpty()) return input — without this, input[0] throws on an empty string.
2. First character uppercase. input[0] returns the first Char. .uppercaseChar() converts it (returns a Char). For ASCII this is fine; Unicode case-folding has subtleties (some characters become two characters in uppercase, like ß → SS).
3. Concatenate. + between Char and String (or String and Char) builds the new string. Strings are immutable, so a new string is allocated.
The modern idiom
Kotlin 1.5 introduced replaceFirstChar, which is the cleanest:
fun capitalize(input: String): String =
input.replaceFirstChar { it.uppercase() }
replaceFirstChar is locale-aware and handles edge cases. The deprecated capitalize() had locale issues (used the system default; could produce i → I in English but I with dot above in Turkish).
it.uppercase() returns a String (handles cases like ß → SS). For single-char output, use it.uppercaseChar() (returns a Char).
fun capitalize(input: String): String =
input.replaceFirstChar { it.uppercaseChar() }
Equivalent for ASCII, slightly more efficient (no string allocation for the converted char).
Why was capitalize() deprecated?
String.capitalize() was a JVM-only Kotlin extension. It used the system's default locale, which produced different output on different systems — a major footgun for "I want consistent capitalization."
replaceFirstChar { it.uppercase() } makes the intent explicit. You can pass a Locale:
input.replaceFirstChar { it.uppercase(Locale.ROOT) }
Locale.ROOT is locale-neutral. Use it whenever you want machine-readable, predictable case conversion.
Title case (every word)
For "make every word's first letter uppercase":
fun titleCase(s: String): String =
s.split(" ").joinToString(" ") { word ->
word.replaceFirstChar { it.uppercaseChar() }
}
println(titleCase("hello world from kotlin")) // "Hello World From Kotlin"
Naive — splits on single space only. Real title-casing is more involved (handle hyphens, apostrophes, articles). For most cases, this is enough.
Sentence case
Sentence case is "first letter of the sentence uppercase, rest lowercase":
fun sentenceCase(s: String): String =
s.lowercase().replaceFirstChar { it.uppercaseChar() }
println(sentenceCase("HELLO WORLD")) // "Hello world"
Lowercase everything first, then uppercase the first char.
Edge cases
Empty string. replaceFirstChar is safe — returns the empty string. The manual version needs the explicit guard.
Single-character string. "k".replaceFirstChar { it.uppercaseChar() } → "K". No substring(1) needed; it's just empty.
Already capitalized. "Kotlin".replaceFirstChar { ... } → "Kotlin" (uppercase of K is still K). Idempotent.
Non-letter first character. "123abc".replaceFirstChar { it.uppercaseChar() } → "123abc". Digits don't have an uppercase form; Char.uppercaseChar() returns the same digit.
Locale-specific. "istanbul".replaceFirstChar { it.uppercaseChar() } → "Istanbul" (ASCII uppercase). With Turkish locale, it.uppercase(Locale.forLanguageTag("tr")) produces "İstanbul" (capital I with dot).
Useful one-liners
// Normalize: trim, lowercase, capitalize first
fun cleanName(s: String): String =
s.trim().lowercase().replaceFirstChar { it.uppercaseChar() }
// First word capitalized, rest unchanged
fun capitalizeFirst(s: String): String =
s.replaceFirstChar { it.uppercaseChar() }
// Make a Map's values title-case
val titledMap = original.mapValues { it.value.replaceFirstChar { c -> c.uppercaseChar() } }
Steering Copilot
If Copilot suggests the deprecated s.capitalize():
// Capitalize the first letter — use replaceFirstChar (capitalize() is deprecated)
Naming the API in the comment usually flips it to the modern path.
If Copilot suggests s[0].toUpperCase():
// In Kotlin 1.5+, prefer Char.uppercaseChar() and String.uppercase() over toUpperCase()
Specifying the version moves Copilot toward the current API.
Common mistakes
Using deprecated capitalize(). Compiler warning, but easy to miss in code review.
Forgetting empty-string guard. s[0] on empty string throws.
Locale assumptions. Default-locale uppercase is non-deterministic across machines.
Mutating a StringBuilder for one-character changes. Overkill. replaceFirstChar is faster and clearer.
Using + for many string concatenations. For one or two, fine. For loops, use StringBuilder or joinToString.
What's next
Episode 6: Jetpack Compose — ViewModel with mutableStateListOf. Manage a list of items in a Compose UI with reactive state.
Recap
replaceFirstChar { it.uppercaseChar() } is the modern Kotlin idiom for capitalizing the first letter. The deprecated capitalize() had locale issues. For empty strings, replaceFirstChar is safe; the manual s[0] + s.substring(1) needs an explicit guard. For predictable case-folding, pass Locale.ROOT. For title-case, split on spaces and replaceFirstChar each word.
Next episode: ViewModel with mutableStateListOf.