What is the difference between String.toInt() and String.toIntOrNull(), and when should you use each?
answer
- toInt throws NumberFormatException; toIntOrNull returns null
- OrNull pairs with Elvis ?:
- Whole family: toLong/Double/Float/Byte/ShortOrNull
- Optional radix argument
- OrNull for untrusted input
basics
~10 stoInt() 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 sBoth 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 linesfun 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 NumberFormatExceptiongo deeper
Knows toInt() throws and toIntOrNull() returns null, and uses Elvis for a default.
Reaches for OrNull on untrusted input, knows the full numeric family and the radix parameter.
Articulates errors-as-values vs exceptions tradeoff, range failures, and composing safe-call chains for validation.
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