Custom Exceptions
In this page:
class CustomException(message: String) : Exception(message)
class DetailedException(val field: Type, message: String) : Exception(message)
throw CustomException("message")
Declaring a Custom Exception
A custom exception class extends Exception (or a subclass of it), typically forwarding a message to the superclass constructor so it can be printed and inspected like any built-in exception.
Example: Declaring a Custom Exception
// Define a class `InsufficientFundsException`
class InsufficientFundsException(message: String) : Exception(message)
// Define the function `withdraw` taking `balance`, `amount` and returning a Double
fun withdraw(balance: Double, amount: Double): Double {
if (amount > balance) throw InsufficientFundsException("Cannot withdraw $amount from balance $balance")
// Return `balance - amount` from this function
return balance - amount
}
// Entry point: execution of the program starts here
fun main() {
try {
withdraw(100.0, 150.0)
} catch (e: InsufficientFundsException) {
// Print "Error: ${e.message}" to the console, with a trailing newline
println("Error: ${e.message}")
}
}
Login to try C/C++/Java/PHP code in the editor
Adding Extra Properties
A custom exception can carry additional properties beyond a message, giving catching code structured information to act on programmatically instead of just parsing text.
Example: Adding Extra Properties
// Define a class `ValidationException`
class ValidationException(val field: String, message: String) : Exception(message)
// Define the function `validateAge` taking `age`
fun validateAge(age: Int) {
if (age < 0) throw ValidationException("age", "Age cannot be negative")
}
// Entry point: execution of the program starts here
fun main() {
try {
validateAge(-5)
} catch (e: ValidationException) {
// Print "Invalid field ${e.field}: ${e.message}" to the console, with a trailing newline
println("Invalid field ${e.field}: ${e.message}")
}
}
Login to try C/C++/Java/PHP code in the editor
Building a Hierarchy of Custom Exceptions
Related custom exceptions can share a common open base class, letting calling code catch either a specific exception type or the more general base type depending on how precise it needs to be.
Example: Building a Hierarchy of Custom Exceptions
open class AppException(message: String) : Exception(message)
// Define a class `NetworkException`
class NetworkException(message: String) : AppException(message)
// Define a class `DatabaseException`
class DatabaseException(message: String) : AppException(message)
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `errors`, set to `listOf(NetworkException("Timeout"), DatabaseException("Connection lost"))`
val errors = listOf(NetworkException("Timeout"), DatabaseException("Connection lost"))
// Loop over `errors`, binding each item to `error`
for (error in errors) {
try {
throw error
} catch (e: AppException) {
// Print "App error: ${e.message}" to the console, with a trailing newline
println("App error: ${e.message}")
}
}
}
Login to try C/C++/Java/PHP code in the editor
Including a Cause
A custom exception's constructor can also accept and forward a cause (another Throwable), preserving the original underlying error while presenting a clearer, higher-level exception to callers.
Example: Including a Cause
// Define a class `DataLoadException`
class DataLoadException(message: String, cause: Throwable) : Exception(message, cause)
// Entry point: execution of the program starts here
fun main() {
try {
try {
throw NumberFormatException("bad number")
} catch (e: NumberFormatException) {
throw DataLoadException("Failed to load data", e)
}
} catch (e: DataLoadException) {
// Print "${e.message}, caused by: ${e.cause?.message}" to the console, with a trailing newline
println("${e.message}, caused by: ${e.cause?.message}")
}
}
Login to try C/C++/Java/PHP code in the editor
- Extending
Throwabledirectly instead ofException(orRuntimeException), which is almost never what you actually want for application-level errors. - Forgetting to pass a message (and optionally a cause) up to the superclass constructor, resulting in exceptions with no useful description when printed.
- Creating overly specific exception subclasses for every tiny situation instead of using a smaller number of well-designed, meaningful exception types.
- A custom exception is typically declared as
class MyException(message: String) : Exception(message). - Extending
Exception(a checked-style base, though Kotlin doesn't enforce checked exceptions) orRuntimeExceptionare both common choices. - Custom exceptions can carry extra properties beyond just a message, useful for programmatic error handling.
- A well-designed set of custom exceptions communicates failure reasons clearly to code that catches them.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: