Error Handling

Overview

Error handling is the process of anticipating, detecting, and resolving anomalies (errors) that occur during the execution of a program. The goal is to prevent the application from crashing and to provide meaningful feedback to the user or developer.

Core Concepts

  • Exceptions: Events that disrupt the normal flow of instructions.
    • Checked Exceptions: Errors that are checked at compile-time (common in Java).
    • Unchecked Exceptions: Runtime errors (e.g., NullPointerException, IndexOutOfBounds).
  • Try-Catch-Finally:
    • Try: The block of code where an exception might occur.
    • Catch: The block that handles the exception if one is thrown.
    • Finally: A block that always executes, regardless of whether an exception was caught, typically used for cleanup (e.g., closing files).
  • Throwing vs. Catching:
    • Throw: Explicitly signaling that an error has occurred.
    • Catch: Intercepting the signal to handle it.
  • Error Hierarchies: Most languages use a class hierarchy for errors (e.g., Error -> TypeError, ReferenceError) to allow catching specific types of errors.

Code Examples

function divide(a: number, b: number): number {
    if (b === 0) {
        throw new Error("DivisionByZeroError: Cannot divide by zero.");
    }
    return a / b;
}

try {
    console.log(divide(10, 0));
} catch (error) {
    if (error instanceof Error) {
        console.error(`Caught an error: ${error.message}`);
    } else {
        console.error("An unknown error occurred.");
    }
} finally {
    console.log("Division attempt complete.");
}

Use Cases

  • Network Requests: Handling timeouts or 404/500 responses from an API.
  • File I/O: Dealing with missing files or permission denied errors.
  • User Input: Validating that input matches expected formats before processing.

Gotchas

  • Empty Catch Blocks: “Swallowing” exceptions by leaving catch blocks empty makes debugging nearly impossible.
  • Over-using Exceptions for Flow Control: Using try-catch for logic that could be a simple if statement (e.g., checking if a key exists in a map) can be slow and confusing.
  • Generic Catch-Alls: Catching the base Error class without narrowing it down can hide unexpected bugs.

Related Notes