Mastering Exception Handling in Java
throw • throws • Nested try • Multiple catch • try-with-resources
Beginner-Friendly | One Concept Per Slide | Real-World Code
What Will You Learn?
Objectives
🎯 Throw exceptions explicitly using the throw
keyword 🔀 Handle multiple exception types with
multiple catch blocks
📢 Declare exceptions using the throws keyword 🪆 Implement nested try blocks for layered error
handling
⚖️ Know the difference between throw and
throws 🔒 Auto-close resources safely using try-with-
resources
The throw Keyword
Section 1 – Explicitly throwing an exception
💡 Simple Definition
throw is used to manually force an exception when something goes wrong in your code.
Syntax: Key Points:
throw new ExceptionName("message");
• Must be inside a method or block
• Stops normal code flow immediately
• Works with any Exception or its subclass
• Control jumps to nearest catch block
🏭 Real-World Analogy
A quality checker on an assembly line finds a defective product and throws it out — stopping the line immediately.
The throws Keyword
Declaring exceptions in a method signature
💡 Simple Definition
throws is written in the method signature to warn the caller: 'this method might throw an exception — be prepared!'
Syntax:
returnType methodName(parameters) throws ExceptionType1, ExceptionType2 { ... }
• Used for checked exceptions (exceptions the compiler forces you to handle)
• You can list multiple exception types, separated by commas
• The caller of this method must handle the exception (using try-catch)
🏨visitorReal-World Analogy: A receptionist declares upfront — 'If your complaint is serious, I will escalate it to the manager.' The
(caller) knows what to expect.
throw vs throws — Side by Side
Know the difference at a glance
Feature throw throws
Purpose Explicitly throw an exception Declare exceptions a method might throw
Where used Inside a method/block In the method signature
Handles how many? One exception instance at a time Multiple types (comma-separated)
Required for checked? Yes — must be caught or declared Yes — must be used if method throws checked
✅ Think of it this way: throw = the action of throwing | throws = the warning label on the method
Code Example — throw (Basic)
Throwing an exception when input is invalid
public class ThrowDemo { Line-by-Line Explanation:
// Method that checks if age is valid
static void validateAge(int age) {
if (age < 0 || age > 150) { validateAge(-5) Calls the method with an invalid age
// Throw an exception if age is wrong
throw new IllegalArgumentException(
"Age must be 0-150"); if (age < 0 || age > 150) Checks if age is out of range
}
[Link]("Valid age: " + age);
} throw new IllegalArgumentException(...) Manually
public static void main(String[] args) { throws an exception — stops here!
try { validateAge(-5); }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) Catches the
[Link]("Caught: "+[Link]()); thrown exception
}
}
} [Link]() Retrieves the error message we set
✅ Output: Caught: Age must be 0-150
Code Example — throws (Basic)
Declaring that a method may throw IOException
import [Link].*; Line-by-Line Explanation:
public class ThrowsDemo { throws IOException
// Declares it might throw IOException
static void readFile(String name) Method warns: 'I might fail with IOException'
throws IOException {
BufferedReader br = new FileReader(name)
new BufferedReader(new FileReader(name));
[Link]([Link]());
Opens a file — this can fail if file missing
[Link]();
}
public static void main(String[] args) {
[Link]()
try { readFile("[Link]"); }
catch (IOException e) { Reads one line from the file
[Link]("Error: " + e);
} catch (IOException e)
}
💡 Key Idea: readFile() doesn't handle the error — it delegates (passes) it to whoever calls it.
} Caller handles the declared exception here
Combined Example — Custom Exception
throw + throws together in a real-world bank scenario
// Step 1: Create a custom exception How It Works — 4 Steps:
class InsufficientFundsException extends Exception {
InsufficientFundsException(String msg) {
super(msg); 1 Create custom exception
}
} Extend Exception class with a message
class BankAccount {
double balance;
// Step 2: Declare with throws 2 Declare with throws
void withdraw(double amount)
throws InsufficientFundsException { Method signature tells callers about the risk
if (amount > balance)
// Step 3: Throw if balance too low
throw new InsufficientFundsException( 3 throw inside method
"Balance too low");
balance -= amount;
}
Manually throw if business rule is violated
}
4 Caller catches it
// Step 4: Caller handles it
[Link](200); // caught → "Balance too low" Handles the error gracefully in main()
Practice Problem — throw & throws
Let's apply what we learned
📝 Problem
Create a method setAge(int age) that throws a custom checked exception InvalidAgeException if age is not between 0
and 120. Declare it with throws. Handle it in main().
• Input: 150 → Output: InvalidAgeException: Age must be 0-120
• Input: 25 → Output: Age set to 25
class InvalidAgeException extends Exception {
InvalidAgeException(String s) { super(s); }
}
class Person {
void setAge(int age) throws InvalidAgeException {
if (age < 0 || age > 120)
throw new InvalidAgeException("Age must be 0-120");
[Link]("Age set to " + age);
}
}
// In main: [Link](150) → InvalidAgeException caught and printed
Multiple catch Blocks
Section 2 – Handling different errors differently
💡 One try block can have many catch blocks — each handles a different type of error.
try { ⚠️ Order Matters!
// code that might fail Specific exceptions must come BEFORE general ones.
} catch (ArithmeticException e) {
'Exception' must always be last — or you'll get a
// handles division errors
} catch (ArrayIndexOutOfBoundsException e) { compile error.
// handles array errors
} catch (Exception e) {
// catches anything else (LAST!)
☑️ Java 7+ Multi-catch
} If two exceptions need same handling, combine with |
catch (IOException | SQLException e) { ... }
🛡️ Why use it?
🔒 Security Analogy: Different security guards catch different problems — one for weapons, one for drugs, one for documents.
Different errors need different responses.
Don't treat all problems the same way!
Code Example — Multiple catch
Catching different exceptions from one try block
public class MultipleCatchDemo { What Happens?
public static void main(String[] args) {
try {
int[] arr = new int[5]; arr[10] = 30 Array only has 5 slots (0–4). Index 10 fails!
arr[10] = 30; // Error! Index 10 doesn't exist
int res = 10 / 0; // This won't even run
} int res = 10/0 Never reached — exception already
// Most specific first: thrown above
catch (ArithmeticException e) {
[Link]("Arithmetic: " + e); ArithmeticException Checked first, but won't match
} here
catch (ArrayIndexOutOfBoundsException e) {
[Link]("Array Index: " + e); ArrayIndexOutOfBoundsException This one matches!
} Caught here.
catch (Exception e) { // Generic — always last
[Link]("Other: " + e);
} Exception Safety net — never reached in this case
}✅bounds for length 5
}
Output: Array Index: [Link]: Index 10 out of
Nested try Blocks
A try block inside another try block
💡[Link] different parts of your code have different risks. Nested try lets you handle them at different
try { // Outer try — big level errors 🔁 Propagation Rule
// ... some code ...
try { // Inner try — specific errors If inner catch doesn't handle the exception,
int x = arr[5] / 0; it automatically travels up to outer catch.
} catch (ArithmeticException e) {
}
// Handles only arithmetic here
} catch (ArrayIndexOutOfBoundsException e) {
🎯 Why use it?
// Inner didn't catch it — outer does! Handle different risks at different points:
} Inner = specific task errors
Outer = broader errors
🔗 Connected finally
🏦 Real-World: In a bank app — outer try handles connection errors; inner try handles SQL query errors.
Each try level can have its own finally block
for cleanup at that level.
Code Example — Nested try
Seeing how exceptions propagate from inner to outer
public class NestedTryDemo { Exception Flow:
public static void main(String[] args) {
try { // OUTER try
int[] arr = {1, 2, 3};
try { // INNER try arr[5]
// arr[5] doesn't exist!
int x = arr[5] / 0; Index 5 out of bounds → exception thrown
} catch (ArithmeticException e) {
// Only handles arithmetic errors
[Link]("Inner: Arithmetic"); Inner catch
}
// Inner didn't catch it...
Checks: ArithmeticException? No, doesn't match.
} catch (ArrayIndexOutOfBoundsException e) {
[Link]("Outer: Array Index");
}
✅
} Propagates up
} Output: Outer catch: Array Index
Exception travels to outer catch block
🔑 Inner catch didn't match → exception 'bubbled up' to outer catch. Outer catch
ArrayIndexOutOfBoundsException? YES! Caught!
Multi-catch — Java 7 Shortcut
Handle multiple exception types with one catch block
💡two Ifidentical
two different exceptions need the same response, combine them with the pipe | symbol instead of writing
catch blocks.
Before Java 7 — Repetitive: Java 7+ — Clean & Efficient:
} catch (NullPointerException e) { } catch (NullPointerException |
[Link]("Error!"); IllegalArgumentException e) {
} catch (IllegalArgumentException e) { [Link]("Error!");
[Link]("Error!"); // same! // One block handles both!
} }
public class MultiCatchDemo {
public static void main(String[] args) {
try { String s = null; [Link](); } // NullPointerException
catch (NullPointerException | IllegalArgumentException e) {
[Link]("Caught: " + [Link]().getSimpleName());
}
✅ Output: Caught: NullPointerException 💡 Use when both exceptions need identical handling.
}
}
Practice Problem — Nested try & Multiple catch
Putting it all together
📝 Problem
• Take two integers and an array index from user
• Outer try: catch InputMismatchException (if user types text instead of a number)
• Inner try: divide the numbers and store result at given index
• Inner catches: ArithmeticException (÷ 0) and ArrayIndexOutOfBoundsException
try { // OUTER — catches bad input
int a = [Link]();
int b = [Link]();
int idx = [Link]();
try { // INNER — catches math/array errors
int res = a / b;
arr[idx] = res;
[Link]("Result: " + arr[idx]);
} catch (ArithmeticException e) {
[Link]("Cannot divide by zero");
} catch (ArrayIndexOutOfBoundsException e) {
[Link]("Array index out of bounds");
}
} catch (InputMismatchException e) {
• [Link]("Please enter integers only");
10, 0, 2 → Cannot divide by zero
try-with-resources
Section 3 – Auto-closing resources safely
💡an error
Resources (files, connections) must be closed after use. try-with-resources does this automatically — even if
occurs!
Syntax:
try (ResourceType resource = new ResourceType()) {
// use the resource here
} catch (Exception e) { /* handle error */ } // resource is ALREADY closed!
📦 AutoCloseable 🔢 Multiple Resources 🎯 When to use
Resource must implement
Declare multiple, separated by File I/O, Database connections, Network
AutoCloseable interface (most Java
semicolon ; sockets —
resources do)
Closed in REVERSE order of declaration anything that needs cleanup after use
close() method is called automatically
🏨it. Hotel Analogy: When you check out, your room key is automatically deactivated — you don't need to remember to return
try-with-resources is that automatic deactivation for resources.
Before vs After — try-with-resources
Why the old way was risky and verbose
❌ Old Way — Verbose and Error-Prone ✅ New Way — Clean and Safe
BufferedReader br = null; try (BufferedReader br =
try { new BufferedReader(
br = new BufferedReader( new FileReader("[Link]"))) {
new FileReader("[Link]"));
[Link]([Link]()); [Link]([Link]());
} catch (IOException e) {
[Link](); } catch (IOException e) {
} finally { [Link]();
if (br != null) { }
try { [Link](); } // [Link]() called automatically!
catch (IOException e) { [Link](); }
}
}
Why is the new way better?
✓ No manual finally needed — close() is called
✓ Safer — Resource closed even if exception occurs
automatically
✓ Cleaner to read — Anyone can understand it
✓ Less code to write — Fewer places where bugs can hide
immediately
Code Example — Multiple Resources
Copying a file using two auto-closed streams
import [Link].*; Explanation:
public class CopyFile { FileInputStream in Opens [Link] for
public static void main(String[] args) { reading
// Both streams declared in one try
try (FileInputStream in = FileOutputStream out Opens [Link] for
new FileInputStream("[Link]"); writing
FileOutputStream out =
new FileOutputStream("[Link]")) { Semicolon between them How we separate
multiple resources
byte[] buffer = new byte[1024];
int len; buffer & [Link]() Reads 1024 bytes at a time
while ((len = [Link](buffer)) > 0) {
from source
[Link](buffer, 0, len);
}
[Link](...) Writes those bytes to
} catch (IOException e) {
destination
[Link]();
}
✅ // BOTH in and out are closed automatically Auto-close order out closes first, then in
(reverse
} Result: Contents of [Link] copied to [Link] — both streams closed safely, no finally order)
block needed!
}
Custom AutoCloseable Resource
Creating your own resource that auto-closes
💡close()Anymethod.
class can work with try-with-resources if it implements the AutoCloseable interface and provides a
// Step 1: Implement AutoCloseable What Happens Step by Step:
class MyResource implements AutoCloseable {
public void use() {
1 new MyResource()
[Link]("Using resource");
}
@Override Resource is created and opened
public void close() throws Exception {
[Link]("Resource closed"); [Link]()
2
}
}
You use the resource — prints 'Using resource'
// Step 2: Use it with try-with-resources 3 try block ends
try (MyResource res = new MyResource()) {
[Link](); // 'Using resource' printed Java automatically calls close()
} // close() called automatically here!
4 close() runs
Practice Problem — try-with-resources
Reading and writing files safely
📝 Problem
Read integers from '[Link]' (one per line) and write their squares to '[Link]'. Use try-with-resources for
both BufferedReader and PrintWriter. Handle IOException.
import [Link].*;
public class SquareNumbers {
public static void main(String[] args) {
// Both files opened — both auto-closed after try block
try (BufferedReader br = new BufferedReader(new FileReader("[Link]"));
PrintWriter pw = new PrintWriter(new FileWriter("[Link]"))) {
String line;
while ((line = [Link]()) != null) {
int num = [Link](line); // convert text to number
[Link](num * num); // write the square
}
} catch (IOException e) {
[Link]("IO Error: " + [Link]());
} catch (NumberFormatException e) {
[Link]("Invalid number format");
[Link]
} input: [Link] output:
}
Summary — What You Learned
throw Explicitly throws an exception from inside a method or block
throws Declares in the method signature that an exception may occur
Multiple catch Handle different exceptions with separate catch blocks — specific first, general last
Nested try Layer your exception handling — uncaught inner exceptions rise to outer catch
Auto-closes resources (files, connections) implementing AutoCloseable — no finally
try-with-resources
needed
Master these 5 concepts and your Java programs will be robust, safe, and easy to maintain!