☕
Core Java Roadmap Phase 04
0 / 40 (0%)
☰ Syllabus Index Next: P05 →

Exception Handling & Diagnostic Resilience Architecture

📂 Repository Module: Module 1_ 02_ExceptionHandling_Demos \ Enterprise Diagnostics
📖 Textbook Alignment: Volume I — Chapter 7: Exceptions, Assertions, and Logging
Phase 4

Exception Handling & Resilience Architecture

📂 Module 1_ Problem Solving & Java programming \\ 02_ExceptionHandling_Demos
📖 Core Java Textbook Alignment: Volume I — Chapter 7: Exceptions, Assertions, and Logging

4.1 Throwable Hierarchy: Checked vs Unchecked Exceptions

📖 Cay S. Horstmann • Core Java Volume I — Chapter 7, Section 7.1 ("Dealing with Errors")
“In Java, an exception object is always an instance of a class derived from Throwable. Checked exceptions represent situations beyond the program's control that the compiler forces you to handle.”
  • Try-With-ResourcesAny AutoCloseable resource closes automatically in reverse order of declaration.
⚡ Pro-Tip: The finally Execution Guarantee
The finally block runs ALWAYS, even after a return statement in try! The only exception is System.exit(0) terminating the JVM process.
💡 Real-World Analogy: Airport Passport Check vs Tripping on your Shoelace
• Checked Exception (Airport Passport Check): You KNOW beforehand that traveling abroad requires a passport, and the border might deny entry. The law (compiler) forces you to have a contingency plan before boarding: you MUST write try-catch or declare throws IOException.
• Unchecked Exception (Tripping on your Shoelace): You don't carry a medical emergency team with you everywhere you walk! Tripping on your shoelace (NullPointerException, ArrayIndexOutOfBoundsException) is simply a careless bug in your code — tie your shoelaces! Fix your code logic instead of littering try-catch blocks everywhere.
• Error (The Airport Runway has an Earthquake): OutOfMemoryError, StackOverflowError. Fatal, unrecoverable system catastrophes. Applications should not attempt to catch these.
🖊 Architectural Diagram: Java Throwable Class Hierarchy [Core Java Vol I Ch 7] Mermaid Diagram
graph TD Throwable["java.lang.Throwable"] Throwable --> Error["java.lang.Error (Fatal System Disasters)"] Throwable --> Exception["java.lang.Exception (Application Conditions)"] Error --> OOM["OutOfMemoryError"] Error --> SOF["StackOverflowError"] Exception --> Checked["Checked Exceptions (Compiler Enforced)
IOException, SQLException"] Exception --> RuntimeException["RuntimeException (Unchecked Bugs)
NullPointerException, IndexOutOfBounds"]
📂 Module 1.../TryWithResourcesDemo.java — Modern Resource Management
import java.io.*;

public class TryWithResourcesDemo {
    public static void main(String[] args) {
        // Try-With-Resources (Java 7+): Any AutoCloseable resource declared in parentheses
        // is GUARANTEED to be closed automatically in reverse order, even if exceptions occur!
        try (BufferedReader reader = new BufferedReader(new FileReader("orders.txt"))) {
            String line = reader.readLine();
            System.out.println("Read: " + line);
        } catch (FileNotFoundException e) {
            System.err.println("Orders file missing: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("I/O error during read: " + e.getMessage());
        }
        // No finally block needed! No manual reader.close() calls! No leak potential!
    }
}
👁 Try-with-Resources & AutoCloseable Lifecycle Breakdown
  • AutoCloseable Interface Any object declared inside try (...) must implement java.lang.AutoCloseable (or Closeable). When execution leaves the try block, the JVM automatically invokes close() on each declared resource.
  • Reverse Order Closure If multiple resources are opened (e.g. try (Connection c = ...; PreparedStatement p = ...; ResultSet rs = ...)), the JVM closes them in strictly reverse order of declaration (rs first, then p, then c), matching optimal cleanup semantics.
  • Suppressed Exceptions If an exception occurs inside the try block AND another exception occurs while closing the resource, Java 7+ attaches the close exception as a Suppressed Exception (accessible via e.getSuppressed()). In classic Java 6 finally blocks, closing exceptions would overwrite and swallow the primary business exception!
📂 StringBuilderPerformanceDemo.java — Mutability & Concatenation Performance
public class StringBuilderPerformanceDemo {
    public static void main(String[] args) {
        // Anti-pattern: String concatenation inside loops creates 5000 garbage objects on Heap!
        long start = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < 5000; i++) {
            str += i; // SLOW: Mints 5000 separate String objects!
        }
        long stringTime = System.currentTimeMillis() - start;

        // Best Practice: StringBuilder mutates an internal dynamic array in-place!
        start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 5000; i++) {
            sb.append(i); // FAST: In-place buffer expansion, 0 garbage objects!
        }
        long sbTime = System.currentTimeMillis() - start;

        System.out.println("String loop time: " + stringTime + "ms | StringBuilder time: " + sbTime + "ms");
    }
}
👁 String vs StringBuilder vs StringBuffer Performance Analysis
  • String (Immutable O(N^2)) In a loop of 5,000 iterations, str += i creates 5,000 intermediate String objects and copies character arrays repeatedly. This floods the JVM Young Generation and triggers heavy Garbage Collection pauses.
  • StringBuilder (Mutable O(N)) Maintains an internal resizable char[] (or byte[] in Java 9+ Compact Strings). Calling append() writes into the existing buffer. When capacity fills, it doubles the buffer size (amortized O(1)). Executes 100x to 1000x faster than String concatenation in loops!
  • StringBuffer (Thread-Safe Legacy) Identical to StringBuilder, except every method is marked synchronized. Use StringBuilder for local method variables (99.9% of use cases). Only use StringBuffer if multiple threads are appending to the same buffer concurrently.
📂 TextBlocksDemo.java — Java 15+ Multiline Text Blocks
public class TextBlocksDemo {
    public static void main(String[] args) {
        // Java 15+ Text Blocks: Clean multiline strings without messy \\n or \\" escaping
        String jsonPayload = """
            {
                "employeeId": 101,
                "role": "SENIOR_BACKEND_ENGINEER",
                "department": "ARCHITECTURE"
            }
            """;

        System.out.println(jsonPayload);
    }
}
👁 Java 15+ Text Blocks Mechanics
  • Triple Double-Quote (""" Opens and closes a multiline string. The opening """ must be followed immediately by a newline — you cannot place content on the same line as the opening delimiter.
  • Incidental Whitespace Stripping The compiler automatically strips leading indentation that aligns with the closing """. You don't have to left-align JSON or SQL code to the edge of the source file; your code stays neatly indented.
  • Escape Sequences Within text blocks, double quotes (") do not need escaping! Ideal for SQL queries, JSON payloads, HTML templates, and XML schemas in backend microservices.
📂 ExceptionHandlingCompleteDemo.java — Multi-Catch & Chaining
import java.io.*;
import java.sql.SQLException;

public class ExceptionHandlingCompleteDemo {

    static class OrderProcessingException extends Exception {
        public OrderProcessingException(String message, Throwable cause) {
            super(message, cause); // Exception Chaining preserves original stack trace!
        }
    }

    public static void processOrder(String file) throws OrderProcessingException {
        try {
            if (file == null) throw new FileNotFoundException("File path is null");
            if (file.equals("db_error")) throw new SQLException("Connection timed out");
        } catch (FileNotFoundException | SQLException e) {
            // Multi-catch (Java 7+): catches related exceptions using pipe '|' operator
            // Wrap and rethrow as high-level domain exception while preserving cause:
            throw new OrderProcessingException("Failed to process order file: " + file, e);
        }
    }

    public static void main(String[] args) {
        try {
            processOrder("db_error");
        } catch (OrderProcessingException e) {
            System.err.println("Caught Domain Error: " + e.getMessage());
            System.err.println("Root Cause: " + e.getCause());
        }
    }
}
👁 Multi-Catch, Exception Chaining & Custom Exceptions Explained
  • Custom Domain Exception Lines 3-7: OrderProcessingException extends Exception creates a checked application exception. In clean backend architecture, low-level technical errors (SQL syntax, network drops) are wrapped into meaningful domain exceptions.
  • Exception Chaining (super(msg, cause)) Line 5: Passing cause (the original SQLException) to super(message, cause) ensures the original stack trace is NOT lost! When viewing logs in Kibana or Datadog, developers can inspect the full root cause chain via e.getCause().
  • Multi-Catch Pipe Operator (|) Line 13: catch (FileNotFoundException | SQLException e) — Eliminates duplicate error handling logic. Rule: In a multi-catch statement, parameter e is implicitly final, and the caught exceptions cannot have an inheritance relationship (e.g. you cannot write catch (IOException | FileNotFoundException e) because FileNotFoundException is already an IOException).
📂 Module 1.../02_ExceptionHandling_Demos/.../InvalidCredentialsException.java & User.java
package com.accenture.ltt.exceptions.customexceptions.solutions;

// 1. Custom Checked Exception: Extends java.lang.Exception
public class InvalidCredentialsException extends Exception {
    private static final long serialVersionUID = 1L;

    public InvalidCredentialsException() { super(); }
    public InvalidCredentialsException(String message) { super(message); }
}

// 2. Service Class throwing Custom Exception
class User {
    String username;
    String password;

    public void validate() throws InvalidCredentialsException {
        if ("admin".equals(username) && "pass@123".equals(password)) {
            System.out.println("Authentication successful!");
        } else {
            // Throw custom exception enforcing business rules
            throw new InvalidCredentialsException("Username or password is invalid.");
        }
    }
}
👁 Custom Checked Exception Design Breakdown
  • Extending Exception Extending java.lang.Exception creates a checked exception, forcing calling code to explicitly handle or declare it with throws. (Extending RuntimeException would create an unchecked exception).
  • Passing Message to super Line 8: super(message) passes the descriptive error text up to Throwable, making it viewable via e.getMessage() and printed in log stack traces.
📂 Module 1.../02_ExceptionHandling_Demos/.../FinallyClause.java
package com.accenture.ltt.exceptions.runtime;

import java.util.InputMismatchException;
import java.util.Scanner;

public class FinallyClause {
    public static void division() {
        Scanner sc = new Scanner(System.in);
        try {
            System.out.println("Enter a and b: ");
            int a = sc.nextInt();
            int b = sc.nextInt();
            int c = a / b;
            System.out.println("Result: " + c);
        } catch (InputMismatchException | ArithmeticException e) {
            System.err.println("Handled exception: " + e.getClass().getSimpleName());
        } finally {
            // GUARANTEED to execute: Even if exceptions occur or return is executed!
            System.out.println("finally block executed: Cleaning up resources...");
            sc.close();
        }
    }
}
👁 The finally Execution Guarantee & Edge Cases
  • Execution Guarantee The finally block executes whether an exception was thrown or not, whether it was caught or not, and even if a return statement is executed inside the try block!
  • Only 2 Ways finally Doesn't Run (1) System.exit(0) terminates the JVM process immediately. (2) Fatal hardware or OS crash (power outage or kernel panic).