Exceptions & Error Handling
What is an exception?
An exception is Kotlin’s way of signalling that something went wrong at runtime — a network failed, a number couldn’t be parsed, a list index was out of range. If you don’t handle it, the app crashes. Good apps anticipate failures and respond gracefully.
try / catch / finally
try {
val number = "abc".toInt() // throws NumberFormatException
} catch (e: NumberFormatException) {
println("Not a valid number")
} finally {
println("This always runs (cleanup)")
}
try as an expression
val number = try {
input.toInt()
} catch (e: NumberFormatException) {
0 // default on failure
}
Throwing your own
fun withdraw(amount: Double) {
if (amount <= 0) throw IllegalArgumentException("Amount must be positive")
// ...
}
// handy precondition helpers
require(amount > 0) { "Amount must be positive" } // throws IllegalArgumentException
checkNotNull(user) { "User must be loaded first" }
The Result type (no exceptions)
Instead of throwing, you can return a Result that is either success or failure — clean for functions that can fail:
fun parseAge(text: String): Result<Int> = runCatching { text.toInt() }
parseAge("25")
.onSuccess { println("Age is $it") }
.onFailure { println("Invalid: ${it.message}") }
Handling errors in coroutines
viewModelScope.launch {
try {
val data = api.getData()
_state.value = UiState.Success(data)
} catch (e: IOException) {
_state.value = UiState.Error("Check your connection")
} catch (e: Exception) {
_state.value = UiState.Error("Something went wrong")
}
}
Best practices
- Catch specific exceptions first, then a general one.
- Never swallow an exception silently — at least log it.
- Show the user a friendly message; keep the technical detail in logs.
- Use
require/checkto validate inputs early.
Summary: Wrap risky code intry/catch, validate inputs withrequire/check, and considerResult/runCatchingfor failable functions. Always fail gracefully with a clear message.