Bird
Raised Fist0
Kotlinprogramming~15 mins

Custom exception classes in Kotlin - Deep Dive

Choose your learning style10 modes available
Overview - Custom exception classes
What is it?
Custom exception classes in Kotlin let you create your own error types to represent specific problems in your program. Instead of using general errors, you define meaningful exceptions that explain what went wrong. This helps make your code clearer and easier to fix when errors happen. Custom exceptions are classes that extend Kotlin's built-in Exception class.
Why it matters
Without custom exceptions, all errors look the same and it becomes hard to tell what caused a problem. This slows down fixing bugs and makes your program less reliable. Custom exceptions let you catch and handle specific problems in a smart way, improving user experience and program stability. They help communicate exactly what went wrong, like a clear signpost on a road.
Where it fits
Before learning custom exceptions, you should understand basic Kotlin classes and how to handle errors with try-catch blocks. After this, you can learn about advanced error handling patterns, like sealed classes for errors or using Result types for safer code.
Mental Model
Core Idea
A custom exception class is a special kind of error you create to clearly name and handle specific problems in your program.
Think of it like...
It's like having a special alarm for your house that only rings when the kitchen smoke detector senses smoke, instead of a general alarm that rings for any problem. This way, you know exactly where the problem is.
┌─────────────────────────────┐
│        Exception Class       │
│  (built-in Kotlin class)     │
└─────────────┬───────────────┘
              │
      ┌───────┴────────┐
      │ CustomException │
      │  (your class)   │
      └─────────────────┘

Usage flow:
try {
  // code that might fail
} catch (e: CustomException) {
  // handle specific error
}
Build-Up - 7 Steps
1
FoundationUnderstanding basic exceptions
🤔
Concept: Learn what exceptions are and how Kotlin uses them to signal errors.
In Kotlin, an exception is an object that represents an error or unexpected event. When something goes wrong, Kotlin throws an exception to stop normal flow. You can catch exceptions using try-catch blocks to handle errors gracefully. Example: try { val result = 10 / 0 } catch (e: ArithmeticException) { println("Cannot divide by zero") }
Result
The program prints: Cannot divide by zero
Understanding exceptions as signals for errors is the foundation for controlling program flow when things go wrong.
2
FoundationUsing try-catch for error handling
🤔
Concept: Learn how to catch and respond to exceptions using try-catch blocks.
Try-catch blocks let you run code that might fail and catch specific exceptions to handle them. Example: try { val text = "abc" val number = text.toInt() // throws NumberFormatException } catch (e: NumberFormatException) { println("Invalid number format") }
Result
The program prints: Invalid number format
Try-catch blocks give you control to respond to errors instead of crashing the program.
3
IntermediateCreating a simple custom exception
🤔Before reading on: do you think a custom exception must have special methods or can it be empty? Commit to your answer.
Concept: You can create your own exception by making a class that extends Exception. It can be empty or have extra info.
Example: class MyCustomException(message: String) : Exception(message) fun checkAge(age: Int) { if (age < 18) { throw MyCustomException("Age must be 18 or older") } } fun main() { try { checkAge(15) } catch (e: MyCustomException) { println(e.message) } }
Result
The program prints: Age must be 18 or older
Knowing that custom exceptions can be simple classes helps you create meaningful error types without extra complexity.
4
IntermediateAdding properties to custom exceptions
🤔Before reading on: do you think custom exceptions can carry extra data besides a message? Commit to your answer.
Concept: Custom exceptions can have extra properties to hold more details about the error.
Example: class ValidationException(val field: String, message: String) : Exception(message) fun validate(name: String) { if (name.isEmpty()) { throw ValidationException("name", "Name cannot be empty") } } fun main() { try { validate("") } catch (e: ValidationException) { println("Error in field: ${e.field}, message: ${e.message}") } }
Result
The program prints: Error in field: name, message: Name cannot be empty
Adding properties to exceptions lets you pass rich error info, making handling and debugging easier.
5
IntermediateCatching multiple custom exceptions
🤔Before reading on: can you catch different custom exceptions separately in Kotlin? Commit to your answer.
Concept: You can catch different custom exceptions in separate catch blocks to handle each error type differently.
Example: class LoginException(message: String) : Exception(message) class PermissionException(message: String) : Exception(message) fun login(user: String) { if (user == "") throw LoginException("User not found") if (user == "guest") throw PermissionException("Guest has no access") } fun main() { try { login("guest") } catch (e: LoginException) { println("Login error: ${e.message}") } catch (e: PermissionException) { println("Permission error: ${e.message}") } }
Result
The program prints: Permission error: Guest has no access
Handling different exceptions separately allows precise responses to different problems.
6
AdvancedBest practices for custom exceptions
🤔Before reading on: should custom exceptions always extend Exception or can they extend Throwable directly? Commit to your answer.
Concept: Custom exceptions should extend Exception (not Throwable) and be meaningful, immutable, and documented for clarity.
Guidelines: - Extend Exception or RuntimeException, not Throwable directly. - Keep exceptions immutable (no changing properties). - Use clear names describing the error. - Include helpful messages. - Avoid using exceptions for normal control flow. Example: class DataNotFoundException(message: String) : Exception(message) fun fetchData(id: Int) { if (id < 0) throw DataNotFoundException("Invalid ID: $id") } fun main() { try { fetchData(-1) } catch (e: DataNotFoundException) { println(e.message) } }
Result
The program prints: Invalid ID: -1
Following best practices ensures your exceptions are clear, safe, and maintainable in real projects.
7
ExpertCustom exceptions and Kotlin sealed classes
🤔Before reading on: do you think sealed classes can replace custom exceptions for error handling? Commit to your answer.
Concept: Sealed classes can represent error types as a closed set, offering a safer alternative to many custom exceptions in Kotlin.
Example: sealed class AppError { data class NetworkError(val code: Int) : AppError() data class ValidationError(val field: String) : AppError() } fun handleError(error: AppError) { when (error) { is AppError.NetworkError -> println("Network error code: ${error.code}") is AppError.ValidationError -> println("Invalid field: ${error.field}") } } // This approach avoids throwing exceptions and uses explicit error values. fun main() { val error = AppError.ValidationError("email") handleError(error) }
Result
The program prints: Invalid field: email
Understanding sealed classes as an alternative to exceptions helps write safer, more predictable error handling code.
Under the Hood
When Kotlin code throws an exception, the runtime creates an instance of the exception class and unwinds the call stack until it finds a matching catch block. Custom exceptions are normal classes inheriting from Exception, so they behave like any object but signal errors. The stack trace is captured to show where the error happened. The JVM uses this to manage program flow during errors.
Why designed this way?
Kotlin inherits exception handling from Java, which uses class inheritance to represent errors. This design allows flexible error types and polymorphic catching. Custom exceptions let developers add meaning to errors without changing the runtime. Alternatives like error codes were less expressive and harder to manage.
┌───────────────┐
│  throw Error │
└───────┬───────┘
        │
        ▼
┌─────────────────────┐
│ Exception instance   │
│ (custom or built-in) │
└─────────┬───────────┘
          │
          ▼
┌───────────────────────────────┐
│ Stack unwinds to catch block   │
│ matching exception type        │
└─────────────┬─────────────────┘
              │
      ┌───────┴────────┐
      │ Exception handled │
      └──────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think custom exceptions must always have extra methods beyond a message? Commit to yes or no.
Common Belief:Custom exceptions need special methods or complex code to be useful.
Tap to reveal reality
Reality:Custom exceptions can be simple classes that just carry a message or extra data; no special methods are required.
Why it matters:Believing this makes learners avoid creating custom exceptions, missing out on clearer error handling.
Quick: Do you think catching Exception catches all errors including system errors? Commit to yes or no.
Common Belief:Catching Exception catches every possible error in Kotlin.
Tap to reveal reality
Reality:Some errors like OutOfMemoryError inherit from Throwable but not Exception, so they are not caught by catching Exception.
Why it matters:Assuming all errors are caught can lead to missed critical failures and unstable programs.
Quick: Do you think using exceptions for normal program flow is a good practice? Commit to yes or no.
Common Belief:Throwing exceptions is fine for regular control flow like checking conditions.
Tap to reveal reality
Reality:Exceptions should represent unexpected errors, not normal conditions; using them for flow hurts performance and clarity.
Why it matters:Misusing exceptions can slow programs and make code harder to understand and maintain.
Quick: Do you think sealed classes and custom exceptions serve the same purpose? Commit to yes or no.
Common Belief:Sealed classes and custom exceptions are interchangeable for error handling.
Tap to reveal reality
Reality:Sealed classes represent error states as values without throwing, while exceptions signal errors by interrupting flow; they serve related but different roles.
Why it matters:Confusing these leads to mixing error handling styles and less predictable code.
Expert Zone
1
Custom exceptions should be immutable to avoid confusing error states during handling.
2
Using meaningful exception names improves debugging and logging clarity in large codebases.
3
Stack traces from custom exceptions help pinpoint error origins but can be expensive to create; avoid throwing exceptions in performance-critical loops.
When NOT to use
Avoid custom exceptions when simple error codes or sealed classes can represent errors more safely and clearly. For predictable error handling, prefer sealed classes or Result types to exceptions which are better for unexpected failures.
Production Patterns
In production, custom exceptions are used to signal domain-specific errors like validation failures or resource not found. They are often logged with context and caught at boundaries to show user-friendly messages or retry logic. Combining custom exceptions with sealed classes or Result wrappers is common for robust error handling.
Connections
Sealed classes in Kotlin
Alternative error representation
Knowing sealed classes helps understand safer, explicit error handling without exceptions, improving program predictability.
Error handling in functional programming
Different approach to errors
Functional programming often avoids exceptions, using types like Either or Result to represent errors, which contrasts with exception throwing but shares the goal of clear error management.
Medical diagnosis process
Categorizing and signaling problems
Just like doctors classify symptoms into specific diagnoses to treat patients effectively, custom exceptions classify errors to handle them precisely in programs.
Common Pitfalls
#1Throwing generic exceptions without clear meaning
Wrong approach:throw Exception("Something went wrong")
Correct approach:class DataMissingException(message: String) : Exception(message) throw DataMissingException("User data missing")
Root cause:Not creating specific exceptions leads to vague error messages and harder debugging.
#2Catching all exceptions and ignoring them
Wrong approach:try { riskyOperation() } catch (e: Exception) { // do nothing }
Correct approach:try { riskyOperation() } catch (e: SpecificException) { handleError(e) }
Root cause:Catching all exceptions without handling hides errors and makes bugs hard to find.
#3Using exceptions for normal control flow
Wrong approach:fun isValid(input: String): Boolean { try { checkInput(input) return true } catch (e: Exception) { return false } }
Correct approach:fun isValid(input: String): Boolean { return input.isNotEmpty() && input.all { it.isLetter() } }
Root cause:Misunderstanding exceptions as normal checks causes performance issues and unclear code.
Key Takeaways
Custom exception classes let you create clear, meaningful error types that improve program clarity and debugging.
They are simple Kotlin classes extending Exception and can carry extra information about the error.
Using specific exceptions helps catch and handle different problems precisely, avoiding vague error handling.
Best practice is to keep exceptions immutable, well-named, and avoid using them for normal program flow.
Alternatives like sealed classes offer safer error handling patterns that complement or replace exceptions in Kotlin.

Practice

(1/5)
1. What is the main purpose of creating a custom exception class in Kotlin?
easy
A. To speed up program execution
B. To define a specific type of error with a clear name
C. To automatically fix errors in code
D. To replace all built-in exceptions

Solution

  1. Step 1: Understand what exceptions represent

    Exceptions represent errors or unexpected events in a program.
  2. Step 2: Purpose of custom exceptions

    Custom exceptions let you name specific error types clearly, making code easier to read and debug.
  3. Final Answer:

    To define a specific type of error with a clear name -> Option B
  4. Quick Check:

    Custom exceptions = clear error types [OK]
Hint: Custom exceptions give clear names to specific errors [OK]
Common Mistakes:
  • Thinking custom exceptions fix errors automatically
  • Believing they speed up code execution
  • Confusing them with replacing built-in exceptions
2. Which of the following is the correct way to declare a custom exception class named MyError in Kotlin?
easy
A. exception MyError extends Exception
B. fun MyError() : Exception
C. class MyError inherits Exception
D. class MyError : Exception()

Solution

  1. Step 1: Recall Kotlin class declaration syntax

    In Kotlin, classes are declared with class ClassName.
  2. Step 2: Inherit from Exception class

    Use colon : to inherit, so class MyError : Exception() is correct.
  3. Final Answer:

    class MyError : Exception() -> Option D
  4. Quick Check:

    Custom exception syntax = class Name : Exception() [OK]
Hint: Use colon : to inherit Exception in class declaration [OK]
Common Mistakes:
  • Using 'fun' instead of 'class' to declare exception
  • Using 'extends' or 'inherits' which are not Kotlin keywords
  • Missing parentheses after Exception
3. What will be the output of this Kotlin code?
class MyException : Exception("Custom error")

fun test() {
  throw MyException()
}

fun main() {
  try {
    test()
  } catch (e: MyException) {
    println(e.message)
  }
}
medium
A. Custom error
B. MyException
C. null
D. No output, program crashes

Solution

  1. Step 1: Understand the custom exception message

    The class passes "Custom error" to Exception constructor, so e.message is "Custom error".
  2. Step 2: Catch block prints the exception message

    The catch block catches MyException and prints e.message, which is "Custom error".
  3. Final Answer:

    Custom error -> Option A
  4. Quick Check:

    Exception message printed = Custom error [OK]
Hint: Exception message prints from e.message in catch block [OK]
Common Mistakes:
  • Expecting class name instead of message
  • Thinking program crashes without output
  • Assuming message is null if not set explicitly
4. Identify the error in this Kotlin custom exception class:
class MyException extends Exception() {}
medium
A. Class body cannot be empty
B. Missing parentheses after class name
C. Using 'extends' instead of ':' for inheritance
D. Exception class cannot be inherited

Solution

  1. Step 1: Check Kotlin inheritance syntax

    Kotlin uses colon ':' for inheritance, not 'extends'.
  2. Step 2: Identify the incorrect keyword

    The code uses 'extends' which is from Java, causing syntax error.
  3. Final Answer:

    Using 'extends' instead of ':' for inheritance -> Option C
  4. Quick Check:

    Kotlin inheritance uses ':' not 'extends' [OK]
Hint: Use ':' not 'extends' for inheritance in Kotlin [OK]
Common Mistakes:
  • Confusing Java syntax with Kotlin
  • Thinking empty class body is invalid
  • Believing Exception cannot be subclassed
5. You want to create a custom exception InvalidAgeException that takes an age value as a property and shows a message like "Invalid age: 15". Which Kotlin code correctly implements this?
hard
A. class InvalidAgeException(val age: Int) : Exception("Invalid age: $age")
B. class InvalidAgeException(age: Int) : Exception("Invalid age: ${age}")
C. class InvalidAgeException(age: Int) : Exception("Invalid age: $age")
D. class InvalidAgeException(age: Int) : Exception("Invalid age: " + age)

Solution

  1. Step 1: Understand primary constructor properties and string interpolation

    In Kotlin, val param: Type creates a read-only property accessible as e.age.
  2. Step 2: Constructor param available in super call

    Params (with or without val) are in scope for superclass constructor, use $age for interpolation (braces optional for simple identifiers).
  3. Step 3: Evaluate options

    A correctly uses val age: Int for property + $age interpolation. B/C/D lack val, so no age property (only private param). D uses concatenation (valid but less idiomatic).
  4. Final Answer:

    class InvalidAgeException(val age: Int) : Exception("Invalid age: $age") -> Option A
  5. Quick Check:

    val age: Int + $age interpolation for property + message [OK]
Hint: Use val age: Int and $age for property + message interpolation [OK]
Common Mistakes:
  • Omitting 'val' (no public age property)
  • Using unnecessary braces ${age} (optional for simple vars)
  • Using string concatenation instead of interpolation
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard