BIT401 Advanced Java Programming

Advanced Java ProgrammingUnit 711 min read

Exception Handling: Try-Catch, Throw, Custom Exceptions, and Best Practices

Unit 7 of Advanced Java Programming covers exception handling mechanisms in Java, including checked vs. unchecked exceptions, the try-catch-finally block, custom exceptions, and best practices for robust error handling. This note explains how exceptions disrupt normal flow, how to handle them gracefully, and how to des

TAKEAWAYS:

  • Exceptions are objects that represent errors or unexpected events in Java, categorized as checked (compile-time) or unchecked (runtime).
  • Use try-catch-finally blocks to handle exceptions gracefully, ensuring resources are released even if an error occurs.
  • Custom exceptions extend Exception or RuntimeException and allow you to define application-specific error conditions.
  • The throws keyword declares exceptions that a method might throw, while throw explicitly throws an exception.
  • Best practices include logging exceptions, avoiding empty catch blocks, and using exceptions for exceptional cases, not control flow.
  • Java provides built-in exception classes like ArithmeticException, NullPointerException, and IOException for common error scenarios.

1. Introduction to Exceptions

Exceptions are objects that represent errors or unexpected events during program execution. They disrupt the normal flow of a program and must be handled to prevent crashes. Java exceptions are categorized into two types:

1.1 Types of Exceptions

Type Description Example Classes
Checked Exceptions Must be handled at compile time (checked by the compiler). IOException, SQLException
Unchecked Exceptions Occur at runtime and are not checked by the compiler (e.g., logical errors). NullPointerException, ArrayIndexOutOfBoundsException
Errors Serious system-level issues (e.g., JVM crashes). Not meant to be caught. OutOfMemoryError, StackOverflowError

Why handle exceptions?

  • Prevents program crashes.
  • Provides meaningful error messages to users.
  • Ensures resources (e.g., file handles, database connections) are released properly.

2. Exception Handling Mechanism

Java uses try-catch-finally blocks to handle exceptions.

2.1 Basic Syntax

try {
    // Code that may throw an exception
} catch (ExceptionType e) {
    // Handle the exception
} finally {
    // Always executes (e.g., cleanup)
}

2.2 Example: Handling ArithmeticException

public class ExceptionDemo {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; // Throws ArithmeticException
        } catch (ArithmeticException e) {
            System.out.println("Cannot divide by zero: " + e.getMessage());
        } finally {
            System.out.println("This always executes.");
        }
    }
}

Output:

Cannot divide by zero: / by zero
This always executes.

TRACE TABLE:

Step Code Executed Exception Thrown? Output
1 int result = 10 / 0; Yes (ArithmeticException) -
2 catch block executes No "Cannot divide by zero: / by zero"
3 finally block executes No "This always executes."

3. The throws and throw Keywords

  • throws: Declares exceptions a method might throw (used in method signature).
  • throw: Explicitly throws an exception (used inside a method).

3.1 Example: throws in Method Signature

import java.io.*;

public class FileReaderDemo {
    public static void readFile(String path) throws IOException {
        FileReader file = new FileReader(path); // May throw IOException
    }

    public static void main(String[] args) {
        try {
            readFile("nonexistent.txt");
        } catch (IOException e) {
            System.out.println("File not found: " + e.getMessage());
        }
    }
}

3.2 Example: throw Keyword

public class AgeValidator {
    public static void validateAge(int age) {
        if (age < 18) {
            throw new ArithmeticException("Age must be 18 or above.");
        }
        System.out.println("Age is valid.");
    }

    public static void main(String[] args) {
        try {
            validateAge(15);
        } catch (ArithmeticException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

Error: Age must be 18 or above.

4. Custom Exceptions

Custom exceptions extend Exception (checked) or RuntimeException (unchecked).

4.1 Example: Custom Exception for Insufficient Balance

class InsufficientBalanceException extends Exception {
    public InsufficientBalanceException(String message) {
        super(message);
    }
}

public class BankAccount {
    private double balance;

    public void withdraw(double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            throw new InsufficientBalanceException("Insufficient balance. Current balance: " + balance);
        }
        balance -= amount;
        System.out.println("Withdrawn: " + amount);
    }

    public static void main(String[] args) {
        BankAccount account = new BankAccount();
        account.balance = 500;
        try {
            account.withdraw(600);
        } catch (InsufficientBalanceException e) {
            System.out.println("Transaction failed: " + e.getMessage());
        }
    }
}

Output:

Transaction failed: Insufficient balance. Current balance: 500.0

REAL WORLD:

  • eSewa (Nepal): Uses custom exceptions to handle payment failures (e.g., InsufficientFundsException when a user tries to pay more than their account balance).
  • Khalti (Nepal): Throws TransactionTimeoutException if a payment does not complete within the expected time.
  • Ncell (Nepal): Validates SIM card PINs and throws InvalidPINException if the user enters the wrong PIN too many times.

5. Best Practices for Exception Handling

  1. Catch specific exceptions: Avoid catching generic Exception unless necessary.
    // Bad: Catches all exceptions
    catch (Exception e) { ... }
    
    // Good: Catch specific exceptions
    catch (FileNotFoundException e) { ... }
    catch (IOException e) { ... }
    
  2. Avoid empty catch blocks: At least log the exception.
    catch (Exception e) {
        System.err.println("Error: " + e.getMessage());
    }
    
  3. Use exceptions for exceptional cases: Do not use them for control flow (e.g., loop termination).
  4. Clean up resources in finally: Ensure file handles, database connections, etc., are closed.
  5. Document exceptions: Use @throws in JavaDoc to specify exceptions a method might throw.

6. Common Built-in Exceptions

Exception Cause Example Scenario
NullPointerException Accessing a null object reference. String s = null; System.out.println(s.length());
ArrayIndexOutOfBoundsException Accessing an invalid array index. int[] arr = {1, 2}; System.out.println(arr[2]);
IOException File or network I/O errors. FileReader file = new FileReader("nonexistent.txt");
NumberFormatException Invalid number format (e.g., parsing). int num = Integer.parseInt("abc");
ClassNotFoundException Class not found during runtime. Class.forName("NonexistentClass");

7. Exception Handling in Real-World Scenarios

Example 1: Daraz Order Processing

Daraz uses exception handling to manage failed orders:

  • If a payment fails, it throws PaymentFailedException.
  • If stock is unavailable, it throws OutOfStockException.
  • The system logs these exceptions and notifies the user.

Mermaid Diagram: Daraz Order Flow

flowchart TD
    A["User places order"] --> B["Check stock"]
    B -->|"Stock available"| C["Process payment"]
    C -->|"Payment succeeds"| D["Ship order"]
    C -->|"Payment fails"| E["Throw PaymentFailedException"]
    B -->|"Stock unavailable"| F["Throw OutOfStockException"]
    E --> G["Notify user"]
    F --> G

Example 2: NEPSE Stock Market

NEPSE uses exception handling to manage invalid trades:

  • If a user enters an invalid stock code, it throws InvalidStockCodeException.
  • If the user’s balance is insufficient, it throws InsufficientFundsException.

Code Example: NEPSE Trade Validation

class InvalidStockCodeException extends Exception {
    public InvalidStockCodeException(String message) {
        super(message);
    }
}

public class StockTrader {
    public static void buyStock(String code, double quantity) throws InvalidStockCodeException {
        if (!isValidStockCode(code)) {
            throw new InvalidStockCodeException("Invalid stock code: " + code);
        }
        System.out.println("Stock purchased: " + code + ", Quantity: " + quantity);
    }

    private static boolean isValidStockCode(String code) {
        return code.matches("[A-Z]{3,4}");
    }

    public static void main(String[] args) {
        try {
            buyStock("ABC", 10);
            buyStock("XYZ1", 5); // Invalid code
        } catch (InvalidStockCodeException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

Stock purchased: ABC, Quantity: 10.0
Error: Invalid stock code: XYZ1

8. Exam Tip

  • For short-answer questions: Define exceptions, try-catch, throws, and throw clearly. Use simple examples like division by zero or array index errors.
  • For coding questions:
    • Always include try-catch blocks where exceptions are expected.
    • Use custom exceptions when designing class hierarchies (e.g., BankAccount with InsufficientBalanceException).
    • Document exceptions using @throws in method comments.
  • Common pitfalls:
    • Forgetting to handle checked exceptions (compile-time errors).
    • Swallowing exceptions without logging or handling them.
    • Using exceptions for control flow (e.g., looping).

Past Exam Question Answer Example: Q: Describe exception handling with an example. A: Exception handling in Java is done using try-catch-finally blocks. When an exception occurs, the normal flow is interrupted, and the catch block executes to handle it. For example:

try {
    int[] arr = {1, 2, 3};
    System.out.println(arr[5]); // Throws ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Error: Index out of bounds.");
} finally {
    System.out.println("Execution complete.");
}

Output:

Error: Index out of bounds.
Execution complete.

This demonstrates how exceptions are caught and handled gracefully. Custom exceptions can also be created by extending Exception or RuntimeException.


ThrowableErrorExceptionCheckedUnchecked
Inheritance hierarchy of Java exceptions (simplified)

Based on the TU BIT syllabus for Advanced Java Programming (BIT401), unit 7.

Discussion

Loading…