Definitions
Exception: Abnormal event disrupting normal program flow. Throwable superclass with Error and Exception branches.
Checked Exception: Must be caught or declared with throws. Compiler enforces handling. Examples: IOException, SQLException, FileNotFoundException.
Unchecked Exception: Runtime exceptions; compiler doesnât enforce handling. Extend RuntimeException. Examples: NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException.
try-catch-finally: Blocks for exception handling. try=monitored code, catch=handling, finally=cleanup (always executes except System.exit()).
throws Keyword: Declares method may throw exceptions. Caller responsible for handling. Allows exception propagation up call stack.
QnA
Whatâs the difference between checked and unchecked exceptions?
Checked exceptions must be caught or declared in the method signature using the throws keywordâthe compiler enforces this handling. Examples include IOException and SQLException, which occur due to external factors. Unchecked exceptions extend RuntimeException and represent programming errors that ideally shouldnât occur with proper code, such as NullPointerException or ArrayIndexOutOfBoundsException. The compiler doesnât enforce handling for unchecked exceptions. Use checked exceptions for recoverable errors; use unchecked for programming mistakes.
Can you have try without catch or finally?
Yes, Java 7+ allows try-with-resources syntax for handling AutoCloseable resources without needing catch or finally blocks. However, traditional try statements must have at least a catch block or finally block (or both). Try-with-resources automatically closes resources even if exceptions occur, providing cleaner syntax than manual try-finally blocks.
Does finally always execute?
Yes, the finally block executes after try and catch blocks in virtually all scenarios. The only exceptions are: calling System.exit() explicitly terminates the JVM before finally runs, a JVM crash, or the thread being terminated forcefully. In normal circumstances, finally provides reliable cleanup code. Note that if catch or try contains a return statement, finally still executes before that return occurs.
What happens if both catch and finally contain return statements?
The finally blockâs return value overrides the catch blockâs return value. Whatever value or exception the finally block returns/throws becomes what the caller receives. This can lead to unexpected behavior if not understood, so itâs generally discouraged to return from finally blocks. If you need to handle exceptions before returning, do so in catch; let finally only perform cleanup.
Can you throw exceptions in finally?
Yes, you can throw exceptions in finally blocks, but doing so will override any exception from try or catch blocks. If you want to preserve both exceptions, use exception chaining: catch the original exception, then throw a new exception with the original as the cause using new ExceptionType("message", originalException). This preserves the exception stack trace.
Whatâs try-with-resources?
Try-with-resources (Java 7+) automatically closes AutoCloseable resources like streams and connections. Syntax: try (ResourceType resource = new Resource()) { }. The resource is automatically closed when the try block exits, whether normally or via exception. This eliminates the need for manual try-finally blocks with resource.close() calls, reducing code and preventing resource leaks.
Code Examples
Example - try-catch-finally:
try {
int[] arr = {1, 2, 3};
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array index out of bounds: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Arithmetic error: " + e.getMessage());
} catch (Exception e) {
System.out.println("General exception: " + e.getMessage());
} finally {
System.out.println("Cleanup code always runs");
}Example - Multiple Catch Blocks (Most specific first):
try {
// Code that may throw exceptions
methodThatThrows();
} catch (FileNotFoundException e) {
// Most specific exception
System.out.println("File not found: " + e);
} catch (IOException e) {
// More general exception
System.out.println("IO error: " + e);
} catch (Exception e) {
// Most general exception
System.out.println("General error: " + e);
}Example - throws Declaration:
public void readFile(String filename) throws IOException {
FileReader reader = new FileReader(filename);
// IOException not caught; delegated to caller
}
public static void main(String[] args) {
try {
readFile("file.txt");
} catch (IOException e) {
System.out.println("Cannot read file: " + e);
}
}Example - try-with-resources (Java 7+):
// Automatically closes BufferedReader
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("IO error: " + e);
}
// br automatically closed, even if exception thrownExample - Custom Exceptions:
public class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
public void validateAge(int age) throws InvalidAgeException {
if (age < 0 || age > 150) {
throw new InvalidAgeException("Age must be between 0 and 150");
}
}
// Usage
try {
validateAge(200);
} catch (InvalidAgeException e) {
System.out.println("Invalid age: " + e.getMessage());
}Example - Exception Chaining:
try {
// Some operation
} catch (SQLException e) {
// Preserve original exception while adding context
throw new ApplicationException("Database error occurred", e);
}
public class ApplicationException extends Exception {
public ApplicationException(String message, Throwable cause) {
super(message, cause);
}
}Key Points
- Exception Hierarchy: Throwable is root, with two branches: Error (system errors) and Exception (application errors). RuntimeException is unchecked; others are checked.
- Catch Order: Arrange catch blocks from most specific to least specific exceptions. Compiler warns if less-specific catch comes before more-specific one (unreachable code).
- Resource Leaks: Always use try-with-resources for AutoCloseable resources (streams, connections, readers). Prevents forgetting close() calls and ensures cleanup even on exceptions.
- Empty Catch Blocks: Never leave catch blocks empty or just print stack traces. Log appropriately or re-throw with context. Silent failures are debugging nightmares.
- Custom Exceptions: Extend Exception for checked exceptions (recoverable errors); extend RuntimeException for unchecked (programming errors). Provide meaningful messages and constructors accepting causes.