What Are Exceptions?
Imagine you're driving a car and suddenly a tire goes flat. You don't just crash - you pull over, fix the problem, and continue. Exceptions in Java work the same way.
An exception is an unexpected event that occurs during program execution - something that disrupts the normal flow of your code. It could be:
- Trying to divide by zero
- Opening a file that doesn't exist
- Accessing an array element that's out of bounds
- Connecting to a server that's offline
- Converting invalid text to a number
Without exception handling, when an error occurs, your program would crash immediately and stop running. With exception handling, you can catch these errors, deal with them gracefully, and allow your program to continue running or exit cleanly.
Exception handling is crucial because:
- Prevents crashes - Your program doesn't just stop when something goes wrong
- Provides user-friendly messages - Instead of cryptic error codes, show helpful messages
- Allows recovery - Give users a chance to correct errors (like re-entering data)
- Maintains data integrity - Clean up resources properly even when errors occur
- Debugging - Helps you understand what went wrong and where
What Happens When an Exception Occurs?
Let's see what happens when code encounters an error:
Example: Division by Zero (Without Exception Handling)
public class CrashExample {
public static void main(String[] args) {
System.out.println("Program started");
int a = 10;
int b = 0;
int result = a / b; // BOOM! Exception thrown here!
System.out.println("Result: " + result); // This line NEVER executes
System.out.println("Program finished"); // This line NEVER executes
}
}
What Actually Happens:
// Console Output:
Program started
Exception in thread "main" java.lang.ArithmeticException: / by zero
at CrashExample.main(CrashExample.java:6)
// Program crashes! The last two lines never execute!
Step-by-step breakdown:
- Program prints "Program started" ✅
- When it tries to divide by zero, Java throws an exception (creates an ArithmeticException object)
- Since there's no exception handler, the program crashes immediately
- The remaining code never runs ❌
- The user sees a scary error message ❌
Try-Catch: Catching Exceptions
Now let's handle that exception properly using a try-catch block!
Example: Handling Division by Zero
public class SafeExample {
public static void main(String[] args) {
System.out.println("Program started");
try {
// Code that might cause an exception
int a = 10;
int b = 0;
int result = a / b; // Exception thrown here!
System.out.println("Result: " + result); // This line is skipped
} catch (ArithmeticException e) {
// Code that runs when exception is caught
System.out.println("Error: Cannot divide by zero!");
System.out.println("Please check your numbers and try again.");
}
System.out.println("Program finished successfully"); // This DOES execute!
}
}
What Actually Happens:
// Console Output:
Program started
Error: Cannot divide by zero!
Please check your numbers and try again.
Program finished successfully
// Program runs to completion! ✅
Step-by-step breakdown:
- Program enters the try block
- When division by zero occurs, Java throws an ArithmeticException
- Java immediately jumps out of the try block (skipping remaining try code)
- Java looks for a matching catch block
- Finds the ArithmeticException catch block and executes that code
- After the catch block, execution continues normally
- Program completes successfully! ✅
If NO exception occurs: Code in try block executes completely → catch block is skipped → program continues
If exception occurs: try block stops at the error → matching catch block executes → program continues
Understanding Exception Objects
When an exception is thrown, Java creates an exception object that contains information about the error.
try {
int[] numbers = {1, 2, 3};
System.out.println(numbers[10]); // Out of bounds!
} catch (ArrayIndexOutOfBoundsException e) {
// 'e' is the exception object - it has useful information!
// Get the error message
System.out.println("Message: " + e.getMessage());
// Output: Message: Index 10 out of bounds for length 3
// Get the exception type
System.out.println("Type: " + e.getClass().getName());
// Output: Type: java.lang.ArrayIndexOutOfBoundsException
// Print the full stack trace (for debugging)
e.printStackTrace();
// Shows exactly where the error occurred in your code
}
Common Exception Methods
- getMessage() - Returns the error message as a String
- printStackTrace() - Prints the full error trace (useful for debugging)
- toString() - Returns exception name and message
- getCause() - Returns the cause of this exception (if any)
Multiple Catch Blocks
Different errors need different handling. You can have multiple catch blocks to handle different types of exceptions:
import java.util.Scanner;
public class MultipleCatchExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
System.out.print("Enter a number: ");
String input = scanner.nextLine();
// Might throw NumberFormatException if input is not a number
int number = Integer.parseInt(input);
// Might throw ArithmeticException if number is 0
int result = 100 / number;
System.out.println("Result: " + result);
} catch (NumberFormatException e) {
// Handles invalid number format
System.out.println("Error: Please enter a valid number!");
System.out.println("You entered: " + e.getMessage());
} catch (ArithmeticException e) {
// Handles division by zero
System.out.println("Error: Cannot divide by zero!");
} catch (Exception e) {
// Catches any other exception
System.out.println("An unexpected error occurred: " + e.getMessage());
}
System.out.println("Program continues...");
}
}
Example Runs:
// Run 1: User enters "abc"
Enter a number: abc
Error: Please enter a valid number!
You entered: For input string: "abc"
Program continues...
// Run 2: User enters "0"
Enter a number: 0
Error: Cannot divide by zero!
Program continues...
// Run 3: User enters "5"
Enter a number: 5
Result: 20
Program continues...
Always put more specific exceptions BEFORE more general ones!
// ✅ CORRECT - Specific first, general last
catch (ArrayIndexOutOfBoundsException e) { }
catch (Exception e) { }
// ❌ WRONG - General first will catch everything!
catch (Exception e) { } // Catches ALL exceptions
catch (ArrayIndexOutOfBoundsException e) { } // Never reached!
The Finally Block
The finally block is a special block that ALWAYS executes, whether an exception occurs or not. It's perfect for cleanup code like closing files or database connections.
import java.io.*;
public class FinallyExample {
public static void main(String[] args) {
FileWriter file = null;
try {
System.out.println("Opening file...");
file = new FileWriter("data.txt");
System.out.println("Writing to file...");
file.write("Hello, World!");
// Simulate an error
int x = 10 / 0; // Exception!
} catch (IOException e) {
System.out.println("IO Error: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Math Error: " + e.getMessage());
} finally {
// This ALWAYS runs - even if there's an exception!
System.out.println("Closing file...");
try {
if (file != null) {
file.close(); // Make sure file is closed
}
} catch (IOException e) {
System.out.println("Error closing file");
}
}
System.out.println("Program finished");
}
}
Output:
Opening file...
Writing to file...
Math Error: / by zero
Closing file... ← Finally block executed!
Program finished
When does finally execute?
- ✅ When try block completes normally
- ✅ When an exception is caught
- ✅ When an exception is NOT caught
- ✅ Even when there's a return statement in try or catch!
- ❌ Only if the JVM exits (System.exit()) or crashes completely
Checked vs Unchecked Exceptions
Java has two categories of exceptions, and understanding the difference is crucial:
1. Checked Exceptions (Compile-Time Exceptions)
These are exceptions that the Java compiler forces you to handle. If you don't handle them, your code won't compile!
Examples: IOException, SQLException, ClassNotFoundException
import java.io.*;
public class CheckedExample {
// ❌ This will NOT compile!
public void readFileBad() {
FileReader file = new FileReader("data.txt"); // Compiler error!
// Error: Unhandled exception: java.io.FileNotFoundException
}
// ✅ Option 1: Handle with try-catch
public void readFileGood1() {
try {
FileReader file = new FileReader("data.txt");
// Use the file...
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
}
// ✅ Option 2: Declare with throws (pass it to caller)
public void readFileGood2() throws FileNotFoundException {
FileReader file = new FileReader("data.txt");
// Now the caller must handle this exception
}
}
2. Unchecked Exceptions (Runtime Exceptions)
These are exceptions that occur during runtime. The compiler doesn't force you to handle them, but you can if you want to.
Examples: NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException
public class UncheckedExample {
// This compiles fine - no try-catch required
public void divide(int a, int b) {
int result = a / b; // Might throw ArithmeticException
System.out.println(result);
}
// But you CAN catch them if you want to handle them
public void divideSafely(int a, int b) {
try {
int result = a / b;
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero!");
}
}
}
Checked Exceptions: For problems you can potentially recover from (file not found, network error)
Unchecked Exceptions: For programming errors that shouldn't happen (null pointer, invalid index)
Throwing Your Own Exceptions
You can create and throw exceptions to signal errors in your own code:
public class BankAccount {
private double balance;
public void withdraw(double amount) {
// Check for negative amount
if (amount < 0) {
// Throw an exception!
throw new IllegalArgumentException(
"Amount cannot be negative: " + amount
);
}
// Check for insufficient funds
if (amount > balance) {
throw new IllegalStateException(
"Insufficient funds. Balance: " + balance + ", Requested: " + amount
);
}
// All checks passed - perform withdrawal
balance -= amount;
System.out.println("Withdrew: $" + amount);
}
}
// Usage:
BankAccount account = new BankAccount();
account.balance = 100;
try {
account.withdraw(-50); // Throws IllegalArgumentException
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
// Output: Error: Amount cannot be negative: -50
}
Try-With-Resources (Automatic Cleanup)
Java 7 introduced a cleaner way to handle resources that need to be closed:
// Old way (lots of code!)
FileReader file = null;
try {
file = new FileReader("data.txt");
// Use file...
} catch (IOException e) {
e.printStackTrace();
} finally {
if (file != null) {
try {
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// New way (automatic cleanup!) ✅
try (FileReader file = new FileReader("data.txt")) {
// Use file...
// File is automatically closed when try block ends!
} catch (IOException e) {
e.printStackTrace();
}
Common Exceptions You'll Encounter
| Exception | When It Occurs | Example |
|---|---|---|
| NullPointerException | Using null reference | String s = null; s.length(); |
| ArrayIndexOutOfBoundsException | Invalid array index | int[] arr = {1,2}; arr[5]; |
| ArithmeticException | Math error (division by zero) | int x = 10/0; |
| NumberFormatException | Invalid number format | Integer.parseInt("abc"); |
| IOException | Input/Output error | Reading non-existent file |
| FileNotFoundException | File doesn't exist | new FileReader("missing.txt"); |
Best Practices
- Be Specific - Catch specific exceptions, not just Exception
- Don't Ignore - Never have empty catch blocks
- Log Errors - Always log exceptions for debugging
- User-Friendly Messages - Show helpful messages to users
- Clean Up Resources - Use finally or try-with-resources
- Don't Use for Control Flow - Exceptions are for exceptional cases
// ❌ BAD - Empty catch (hides errors!)
try {
riskyOperation();
} catch (Exception e) {
// Silent failure - bad!
}
// ✅ GOOD - Handle properly
try {
riskyOperation();
} catch (IOException e) {
logger.error("Failed to perform operation", e);
System.out.println("An error occurred. Please try again.");
}