Skip to main content

Exception Handling

Trushi Jasani
EditReport

Exception Handling

What are Exceptions?โ€‹

Exceptions are runtime errors that disrupt the normal flow of a program. Kotlin provides structured exception handling using try, catch, finally, and throw.

Basic try-catchโ€‹

fun main() {
try {
val result = 10 / 0
println(result)
} catch (e: ArithmeticException) {
println("Error: ${e.message}")
}
}
// Output: Error: / by zero

try-catch-finallyโ€‹

finally always runs, regardless of whether an exception occurred:

fun main() {
try {
val nums = arrayOf(1, 2, 3)
println(nums[10]) // Index out of bounds
} catch (e: ArrayIndexOutOfBoundsException) {
println("Caught: ${e.message}")
} finally {
println("This always executes")
}
}

Multiple Catch Blocksโ€‹

fun parseInput(input: String) {
try {
val num = input.toInt()
println(100 / num)
} catch (e: NumberFormatException) {
println("Not a number: $input")
} catch (e: ArithmeticException) {
println("Cannot divide by zero")
} catch (e: Exception) {
println("Unknown error: ${e.message}")
}
}

fun main() {
parseInput("abc") // Not a number: abc
parseInput("0") // Cannot divide by zero
parseInput("5") // 20
}

try as an Expressionโ€‹

fun toInt(str: String): Int {
return try {
str.toInt()
} catch (e: NumberFormatException) {
-1 // Default value on error
}
}

fun main() {
println(toInt("42")) // 42
println(toInt("abc")) // -1
}

Throwing Exceptionsโ€‹

fun divide(a: Int, b: Int): Int {
if (b == 0) throw ArithmeticException("Divisor cannot be zero")
return a / b
}

fun main() {
try {
println(divide(10, 2)) // 5
println(divide(10, 0)) // Throws exception
} catch (e: ArithmeticException) {
println("Error: ${e.message}")
}
}

Custom Exceptionsโ€‹

class InsufficientFundsException(amount: Double) :
Exception("Insufficient funds: need $$amount more")

class BankAccount(private var balance: Double) {
fun withdraw(amount: Double) {
if (amount > balance) {
throw InsufficientFundsException(amount - balance)
}
balance -= amount
println("Withdrew $$amount. Balance: $$balance")
}
}

fun main() {
val account = BankAccount(1000.0)
try {
account.withdraw(500.0) // OK
account.withdraw(600.0) // Throws
} catch (e: InsufficientFundsException) {
println(e.message)
}
}

require, check, errorโ€‹

Kotlin provides built-in functions for pre/post-condition checks:

fun setAge(age: Int) {
require(age >= 0) { "Age must be non-negative, got $age" }
require(age <= 150) { "Age seems unrealistic: $age" }
println("Age set to $age")
}

fun getUser(id: Int): String? {
val user = if (id == 1) "Alice" else null
checkNotNull(user) { "User with id=$id not found" }
return user
}

fun notImplemented(): Nothing = error("Feature not implemented yet")

fun main() {
setAge(25)
// setAge(-5) // Throws IllegalArgumentException

try {
getUser(99) // Throws IllegalStateException
} catch (e: IllegalStateException) {
println(e.message)
}
}

Exception Hierarchyโ€‹

Throwable
โ”œโ”€โ”€ Error (JVM-level, not usually caught)
โ””โ”€โ”€ Exception
โ”œโ”€โ”€ RuntimeException
โ”‚ โ”œโ”€โ”€ NullPointerException
โ”‚ โ”œโ”€โ”€ ArithmeticException
โ”‚ โ”œโ”€โ”€ ArrayIndexOutOfBoundsException
โ”‚ โ”œโ”€โ”€ NumberFormatException
โ”‚ โ”œโ”€โ”€ ClassCastException
โ”‚ โ””โ”€โ”€ IllegalArgumentException
โ”‚ โ””โ”€โ”€ IllegalStateException
โ””โ”€โ”€ IOException
โ””โ”€โ”€ FileNotFoundException

Catching Multiple Exception Typesโ€‹

fun riskyOp(input: String) {
try {
val n = input.toInt()
println(10 / n)
} catch (e: NumberFormatException) {
println("Not a number")
} catch (e: ArithmeticException) {
println("Division by zero")
}
}

Summaryโ€‹

ConstructPurpose
try { }Wrap risky code
catch (e: Type) { }Handle specific exception
finally { }Always runs (cleanup code)
throw Exception()Manually throw an exception
require(condition)Validate function arguments
check(condition)Validate object/program state
error("message")Throw IllegalStateException
Custom exceptionExtend Exception class
Telemetry Integration

Completed working through this block? Sync progress to workspace.