skip to content

String Extension API

The String extensions cover the operations you would otherwise hand-roll: substringBefore and After, split, trimIndent, padStart, removePrefix, and the safe toIntOrNull-style conversions. Preferring the OrNull parsers over exception-driven parsing is what interviewers look for.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

6

What is the difference between String.toInt() and String.toIntOrNull(), and when should you use each?

level: juniorimportance: must knowfreq 75%

answer

  1. toInt throws NumberFormatException; toIntOrNull returns null
  2. OrNull pairs with Elvis ?:
  3. Whole family: toLong/Double/Float/Byte/ShortOrNull
  4. Optional radix argument
  5. OrNull for untrusted input

basics

~10 s

toInt() converts text to a number but crashes with an error if the text is not a valid number. toIntOrNull() returns null instead of crashing, so you can handle bad input safely.

solid answer

~40 s

Both parse a String into an Int. toInt() throws NumberFormatException when the string is not a valid integer (or out of Int range), so it is appropriate only when you already trust the input. toIntOrNull() returns Int? — a valid Int on success or null on any failure — letting you handle invalid input without try/catch. The OrNull form pairs naturally with the Elvis operator (str.toIntOrNull() ?: 0) or safe calls. The same pattern exists for toLongOrNull, toDoubleOrNull, toFloatOrNull, toByteOrNull, toShortOrNull. Prefer OrNull for any external/user input; reserve the throwing variant for invariants you control. Note toIntOrNull also accepts an optional radix parameter for non-decimal bases.

code

kotlin · 7 lines
kotlin
fun parsePort(raw: String): Int =
    raw.trim().toIntOrNull()?.takeIf { it in 1..65535 } ?: 8080

println(parsePort("3000"))   // 3000
println(parsePort("oops"))   // 8080 (toIntOrNull -> null -> Elvis)
println(parsePort("99999"))  // 8080 (out of valid range)
// "abc".toInt() would throw NumberFormatException

go deeper

for a junior

Knows toInt() throws and toIntOrNull() returns null, and uses Elvis for a default.

for a middle

Reaches for OrNull on untrusted input, knows the full numeric family and the radix parameter.

for a senior

Articulates errors-as-values vs exceptions tradeoff, range failures, and composing safe-call chains for validation.

for a principal

Frames parsing strategy across an API boundary (fail-fast vs tolerant), and standardizes a team convention for input validation vs invariants.

## The two parsing styles Kotlin's stdlib gives every numeric type two String-to-number extension functions: a **throwing** one and a **null-returning** one. - `String.toInt(): Int` — parses the receiver as a base-10 integer. On failure it throws `NumberFormatException` (a subclass of `IllegalArgumentException`). - `String.toIntOrNull(): Int?` — returns the parsed `Int`, or `null` if the string is not a valid integer or is outside `Int`'s range (`-2_147_483_648..2_147_483_647`). ## Why two forms exist The `OrNull` variant turns an exceptional condition into a value you can branch on, which is cheaper and clearer than wrapping a call in `try/catch`. It composes with Kotlin's null-handling operators: ```kotlin val count = userInput.toIntOrNull() ?: 0 // default on failure val port = arg.toIntOrNull()?.coerceIn(1, 65535) // safe-call chain if (s.toIntOrNull() != null) { /* valid */ } ``` ## What counts as valid - Optional leading `+`/`-` sign, then digits. No whitespace, no decimal point, no underscores, no thousands separators. - `" 42 "`, `"42.0"`, `"1_000"`, `""`, and `"abc"` all return `null` from `toIntOrNull()` (and throw from `toInt()`). - Out-of-range values like `"9999999999"` also fail for `Int` (use `toLongOrNull()`). ## Radix Both accept an optional radix: `"ff".toIntOrNull(16) == 255`, `"1010".toInt(2) == 10`. ## The whole family The same throwing / `OrNull` pair exists for `toLong`, `toDouble`, `toFloat`, `toByte`, `toShort`, and (in newer stdlib) unsigned types. **Rule of thumb:** use the `OrNull` form for any data you did not produce (user input, files, network); use the throwing form only when a non-numeric string would be a genuine bug.

  • How would you parse a hexadecimal string like "1A"?
    Pass a radix: "1A".toIntOrNull(16) returns 26, or "1A".toInt(16) which throws on invalid hex.
  • Does toIntOrNull() trim whitespace for you?
    No. " 42 ".toIntOrNull() is null. You must .trim() first if leading/trailing spaces are expected.

toInt() is a strict gatekeeper who slams the door (throws) on a bad ticket; toIntOrNull() quietly hands back nothing so you decide what to do.

saying these in an interview costs you the question

  • Claiming toInt() returns null or 0 on bad input
  • Wrapping toInt() in try/catch when toIntOrNull() is the idiomatic tool
  • Thinking toIntOrNull() trims or accepts decimals/underscores
  • Not knowing the out-of-range case also yields null

context

open as a page

Explain isBlank/isEmpty, ifBlank/ifEmpty, and padStart/padEnd. How do they differ and how do they compose for input normalization?

level: middleimportance: must knowfreq 65%

basics

~10 s

isEmpty checks for zero length; isBlank also treats whitespace-only as empty. ifBlank/ifEmpty give a fallback value when the string is blank/empty. padStart/padEnd add filler characters to reach a target width.

open as a page

Explain substringBefore, substringAfter, substringBeforeLast, and substringAfterLast, including their delimiter and missingDelimiterValue behavior.

level: middleimportance: should knowfreq 60%

basics

~20 s

They slice a string around a chosen marker. 'Before' keeps the part to the left of the marker, 'After' keeps the part to the right. The 'Last' versions look for the last occurrence instead of the first.

open as a page

Compare trimIndent() and trimMargin(): how does each remove leading whitespace from multi-line strings, and what are the gotchas?

level: middleimportance: should knowfreq 55%

basics

~20 s

Both clean up the indentation of multi-line text you wrote inside indented code. trimIndent removes the common leading spaces automatically. trimMargin removes everything up to a marker character you put at the start of each line (default '|').

open as a page

Contrast replace (String vs Char vs regex overloads), removePrefix/removeSuffix, and String.format("%.2f"). What are the common mistakes?

level: seniorimportance: should knowfreq 50%

basics

~10 s

replace swaps text for other text. removePrefix/removeSuffix strip a known beginning or ending only if it's there. format builds a string from a pattern, like showing a number with two decimals using %.2f.

open as a page

How does String.split() behave with String/Char delimiters, the limit parameter, and ignoreCase — and how does it differ from the regex overload?

level: seniorimportance: should knowfreq 48%

basics

~20 s

split breaks a string into a list of pieces around a separator. You can give one or more separators, cap how many pieces you get with limit, and ignore case. There is also a version that splits on a regex pattern.

open as a page