Throwable HierarchyAn exception is an abnormal event that occurs during the execution of a program, disrupting the normal flow of instructions. When an error occurs within a method, the JVM instantiates an Exception Object containing the exception type, error message, and the exact state of the thread Call Stack (Stack Trace) and hands it to the runtime system.
Errors vs. Exceptions:
Error (Irrecoverable System Failures): Severe environmental conditions external to the application (e.g., OutOfMemoryError, StackOverflowError). Applications should not attempt to catch or handle errors; they indicate catastrophic JVM hardware or memory failure.Exception (Recoverable Application Conditions): Exceptional conditions that a well-written application can catch, handle, and gracefully recover from (e.g., FileNotFoundException, NumberFormatException).OutOfMemoryErrorStackOverflowError
IOException, SQLException
NullPointerException, ArithmeticException
Java enforces a strict distinction between checked and unchecked exceptions:
Exception (excluding RuntimeException). They represent anticipated external failures outside direct program control (e.g., missing network files, database disconnection). The Java compiler enforces the Catch-or-Declare Rule: a method that calls code throwing a checked exception must either catch it via try-catch or declare it in its signature via throws.
RuntimeException. They typically represent programming logic bugs (e.g., accessing an invalid array index, dividing by zero, dereferencing a null pointer). The compiler does not verify or require handling of unchecked exceptions.
| Characteristic | Checked Exceptions | Unchecked Exceptions |
|---|---|---|
| Inheritance Superclass | Directly extends java.lang.Exception |
Extends java.lang.RuntimeException |
| Compiler Verification | Strictly verified at compile time | Ignored by compiler (Occurs at runtime) |
| Catch-or-Declare Rule | Mandatory (Must handle or declare with throws) |
Optional |
| Root Cause | External environmental failures (I/O, Network, DB) | Internal programming bugs & bad logic |
| Examples | IOException, SQLException, ClassNotFoundException |
NullPointerException, ArithmeticException, IndexOutOfBoundsException |
try, catch, and finally Block Contracttry Block: Encloses risky code that could throw an exception. A try block must be followed by at least one catch block or a finally block.catch Block: Intercepts and handles an exception object matching its declared parameter type. Multiple catch blocks evaluate from top to bottom.finally Block: A block guaranteed to execute unconditionally, whether an exception occurred or not, whether it was successfully handled or not, and even if a return statement was executed inside try or catch! Used for releasing expensive system resources (closing database sockets, file handles).
Child exceptions must always precede Parent exceptions in multiple catch blocks!
Placing catch (Exception e) before catch (ArithmeticException e) causes a compile error: unreachable code, because the parent catch block intercepts everything first.
Multi-Catch (Java 7+): Multiple unrelated exceptions can be caught within a single catch block using the pipe operator:
catch (ArithmeticException | NumberFormatException e) { ... } (Note: in a multi-catch, parameter e is implicitly final).
finally Block NOT Execute? (Viva Classic)The finally block executes in 99.9% of scenarios. The only exceptions are:
System.exit(0) is invoked inside try or catch (terminates the JVM immediately).Error occurs (such as an unrecoverable hardware segmentation fault).throw vs. throws Keywords & Custom Exceptionsthrow vs. throws Architectural Differencesthrow (Action): A statement used to explicitly trigger an exception instance inside a method body: throw new IllegalArgumentException("Invalid age");. Control transfers immediately to the nearest matching enclosing catch block.
throws (Contract): A clause in the method signature that declares to callers what checked exceptions this method might propagate without handling: public void readFile() throws IOException { ... }.
In enterprise software, standard Java exceptions (like NullPointerException) fail to describe specific domain failures. Developers author custom exception classes:
Exception to create a Checked Custom Exception (forces callers to handle it, e.g., InsufficientFundsException).RuntimeException to create an Unchecked Custom Exception (e.g., AccountSuspendedException).| Exception Class | Type | Trigger Cause | Defensive Prevention Strategy |
|---|---|---|---|
ArithmeticException |
Unchecked | Integer division or modulus by zero (e.g., 10 / 0). Note: Floating-point 10.0 / 0.0 returns Infinity! |
Verify divisor != 0 before arithmetic calculation. |
NullPointerException |
Unchecked | Invoking methods or accessing fields on a null reference. |
Use Objects.requireNonNull(), Optional<T>, or defensive null checks. |
ArrayIndexOutOfBoundsException |
Unchecked | Accessing an array with negative index or index >= length. |
Traverse via enhanced for-each loops or verify index < arr.length. |
NumberFormatException |
Unchecked | Attempting to parse an alphanumeric string into a numeric type (e.g., Integer.parseInt("abc")). |
Validate input string with regular expressions or wrap in try-catch. |
IOException |
Checked | Failed file system read/write, closed network sockets, missing files. | Use Java 7 try-with-resources to ensure streams close automatically. |
This comprehensive application unites all exception concepts:
custom checked domain exceptions (InsufficientFundsException), input validation with NumberFormatException handling, throws propagation, nested try-catch blocks, and a guaranteed finally audit logger.
/**
* DevAscent Academy — Unit 7 Capstone Project
* Demonstrates Checked/Unchecked Exceptions, Custom Exceptions, and Try-Catch-Finally.
*/
// 1. Custom Checked Business Domain Exception
class InsufficientFundsException extends Exception {
private final double deficit;
public InsufficientFundsException(String message, double deficit) {
super(message);
this.deficit = deficit;
}
public double getDeficit() { return this.deficit; }
}
// 2. Banking Ledger Service
public class ResilientBankingEngine {
private double balance = 1000.00;
// Method declaring checked exception via 'throws'
public void withdraw(String amountInput) throws InsufficientFundsException {
System.out.println("Processing Withdrawal Request for: '" + amountInput + "'");
double parsedAmount;
try {
// May throw NumberFormatException (Unchecked)
parsedAmount = Double.parseDouble(amountInput);
} catch (NumberFormatException nfe) {
System.out.println(" [ERROR] Malformed numeric input! Aborting transaction.");
return;
}
try {
if (parsedAmount > this.balance) {
double shortBy = parsedAmount - this.balance;
// Explicitly trigger custom checked exception via 'throw'
throw new InsufficientFundsException("Overdraft Limit Exceeded.", shortBy);
}
this.balance -= parsedAmount;
System.out.printf(" [SUCCESS] Dispensed: $%.2f | Remaining Balance: $%.2f%n",
parsedAmount, this.balance);
} finally {
// Guaranteed cleanup audit logger
System.out.println(" [FINALLY AUDIT] Ledger snapshot completed. DB connection released.");
}
}
public static void main(String[] args) {
System.out.println("==================================================");
System.out.println(" DEVASCENT RESILIENT BANKING TRANSACTION DEMO ");
System.out.println("==================================================");
ResilientBankingEngine atm = new ResilientBankingEngine();
// Test Case 1: Valid Withdrawal
try {
atm.withdraw("300.00");
} catch (InsufficientFundsException e) {
System.out.println("Caught exception: " + e.getMessage());
}
System.out.println("--------------------------------------------------");
// Test Case 2: Malformed Input (NumberFormatException handled gracefully)
try {
atm.withdraw("one_hundred_usd");
} catch (InsufficientFundsException e) {
System.out.println("Caught exception: " + e.getMessage());
}
System.out.println("--------------------------------------------------");
// Test Case 3: Overdraft Custom Checked Exception
try {
atm.withdraw("2500.00");
} catch (InsufficientFundsException ife) {
System.out.printf(" [HANDLED CUSTOM] %s (Deficit Amount: $%.2f)%n",
ife.getMessage(), ife.getDeficit());
}
System.out.println("==================================================");
}
}
Exception (excluding RuntimeException). They represent external environmental conditions that can fail (e.g., IOException). The compiler strictly enforces the Catch-or-Declare rule: code must either catch them in a try-catch or declare them with throws. Unchecked Exceptions inherit from RuntimeException and represent programming flaws (e.g., NullPointerException, ArithmeticException). The compiler does not verify or mandate handling of unchecked exceptions.
throw and throws?throw is an executable keyword statement used inside a method body to explicitly trigger a single exception instance (e.g., throw new MyException();). throws is an identifier clause in the method signature used to declare the types of checked exceptions that the method might propagate to its callers without handling internally (e.g., void process() throws IOException, SQLException).
finally block execute if there is a return statement inside the try block?finally block is guaranteed to execute before the method returns to the caller. When the JVM encounters a return statement in a try or catch block, it pauses return execution, transfers control to execute the finally block, and only after the finally block finishes does the method actually return.
finally block FAIL to execute?finally block fails to execute only when:
System.exit(int status), which halts and shuts down the JVM process immediately.VirtualMachineError, OS segmentation fault) kills the process.Exception) is placed before a child exception (e.g., NullPointerException), the parent block will intercept all occurrences of the child exception because of polymorphic IS-A inheritance. Consequently, the subsequent child catch block could never be reached, and the Java compiler throws a compile-time error: Unreachable catch block.
catch (IOException | SQLException e)). The rule governing multi-catch is that the exception parameter e is implicitly final and cannot be reassigned within the catch block. Furthermore, the caught exceptions cannot have an inheritance relationship (i.e., you cannot write catch (FileNotFoundException | IOException e)).
Error and Exception in the Throwable hierarchy?Error and Exception inherit from java.lang.Throwable. Error represents catastrophic environmental failures (e.g., OutOfMemoryError, StackOverflowError) that an application cannot anticipate or recover from; application code should not attempt to catch Errors. Exception represents programmatic or external conditions that a well-written system can catch and recover from gracefully (e.g., FileNotFoundException).
10 / 0) throws a runtime ArithmeticException: / by zero. In contrast, floating-point division by zero (e.g., 10.0 / 0.0 or 10.0f / 0) adheres to IEEE 754 floating-point standards and does NOT throw an exception; instead, it returns special floating-point constants: Infinity, -Infinity, or NaN (Not a Number, for 0.0 / 0.0).