Kotlin Exception Handling
Managing errors and unexpected situations gracefully
๐ก๏ธ What is Exception Handling?
Exception handling manages runtime errors gracefully, preventing crashes and providing meaningful feedback. Kotlin uses try-catch blocks to handle exceptions and maintain program stability when unexpected situations occur during execution.
// Basic exception handling
try {
val result = 10 / 0
println("Result: $result")
} catch (e: ArithmeticException) {
println("Error: Cannot divide by zero!")
}
Output:
Error: Cannot divide by zero!
Exception Handling Components
Try Block
Code that might throw exceptions
try { /* risky code */ }
Catch Block
Handle specific exception types
catch (e: Exception) { }
Finally Block
Code that always executes
finally { /* cleanup */ }
Throw
Create and throw custom exceptions
throw Exception("Error")
๐น Try-Catch-Finally
Complete exception handling structure:
fun divideNumbers(a: Int, b: Int): String {
return try {
val result = a / b
"Result: $result"
} catch (e: ArithmeticException) {
"Error: Division by zero is not allowed"
} catch (e: Exception) {
"Error: Something went wrong - ${e.message}"
} finally {
println("Division operation completed")
}
}
// Test the function
println(divideNumbers(10, 2))
println(divideNumbers(10, 0))
println(divideNumbers(15, 3))
Output:
Division operation completed
Result: 5
Division operation completed
Error: Division by zero is not allowed
Division operation completed
Result: 5
๐น Common Exception Types
Handle different types of exceptions:
fun demonstrateExceptions() {
// NumberFormatException
try {
val number = "abc".toInt()
} catch (e: NumberFormatException) {
println("Invalid number format: ${e.message}")
}
// IndexOutOfBoundsException
try {
val list = listOf(1, 2, 3)
println(list[5])
} catch (e: IndexOutOfBoundsException) {
println("Index out of bounds: ${e.message}")
}
// NullPointerException
try {
val text: String? = null
println(text!!.length)
} catch (e: KotlinNullPointerException) {
println("Null pointer exception occurred")
}
}
demonstrateExceptions()
Output:
Invalid number format: For input string: "abc"
Index out of bounds: Index: 5, Size: 3
Null pointer exception occurred
๐น Custom Exceptions
Create and throw your own exception types:
// Custom exception class
class InvalidAgeException(message: String) : Exception(message)
class BankAccountException(message: String) : Exception(message)
// Functions that throw custom exceptions
fun validateAge(age: Int) {
if (age < 0) {
throw InvalidAgeException("Age cannot be negative: $age")
}
if (age > 150) {
throw InvalidAgeException("Age seems unrealistic: $age")
}
println("Valid age: $age")
}
fun withdraw(balance: Double, amount: Double) {
if (amount > balance) {
throw BankAccountException("Insufficient funds: $balance < $amount")
}
println("Withdrawal successful: $amount")
}
// Using custom exceptions
try {
validateAge(-5)
} catch (e: InvalidAgeException) {
println("Age validation error: ${e.message}")
}
try {
withdraw(100.0, 150.0)
} catch (e: BankAccountException) {
println("Banking error: ${e.message}")
}
Output:
Age validation error: Age cannot be negative: -5
Banking error: Insufficient funds: 100.0 < 150.0
๐น Try as Expression
Use try-catch as an expression to return values:
// Try as expression
fun safeParseInt(input: String): Int {
return try {
input.toInt()
} catch (e: NumberFormatException) {
0 // Default value
}
}
// Multiple catch blocks as expression
fun processInput(input: String): String {
val result = try {
val number = input.toInt()
when {
number > 0 -> "Positive: $number"
number < 0 -> "Negative: $number"
else -> "Zero"
}
} catch (e: NumberFormatException) {
"Not a number: $input"
} catch (e: Exception) {
"Unknown error: ${e.message}"
}
return result
}
// Test the functions
println("Parse '123': ${safeParseInt("123")}")
println("Parse 'abc': ${safeParseInt("abc")}")
println("Process '42': ${processInput("42")}")
println("Process 'hello': ${processInput("hello")}")
Output:
Parse '123': 123
Parse 'abc': 0
Process '42': Positive: 42
Process 'hello': Not a number: hello