Introduction
Exception is an abnormal event that disrupts normal program flow. Exception handling provides a way to handle runtime errors gracefully.
What is Exception?
Exception = unexpected problem during program execution
Examples:
- Dividing by zero
- File not found
- Array index out of bounds
- Null pointer access
- Network connection failure
Without Exception Handling
public class Main {
public static void main(String[] args) {
int a = 10;
int b = 0;
int result = a / b; // Runtime error: ArithmeticException
System.out.println(result); // Never executes
System.out.println("Program end"); // Never executes
}
}
Output:
Exception in thread "main" java.lang.ArithmeticException: / by zero
Program crashes and stops.
With Exception Handling
public class Main {
public static void main(String[] args) {
try {
int a = 10;
int b = 0;
int result = a / b; // Exception occurs
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero!");
}
System.out.println("Program continues..."); // Executes!
}
}
Output:
Cannot divide by zero!
Program continues...
Program handles error and continues.
Exception Handling Keywords
| Keyword | Purpose |
|---|---|
| try | Code that may throw exception |
| catch | Handle the exception |
| finally | Always executes (cleanup) |
| throw | Manually throw exception |
| throws | Declare exceptions method can throw |
try-catch Syntax
try {
// Code that may throw exception
} catch (ExceptionType e) {
// Handle exception
}
Simple Examples
ArithmeticException:
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0;
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
NullPointerException:
public class Main {
public static void main(String[] args) {
try {
String str = null;
System.out.println(str.length());
} catch (NullPointerException e) {
System.out.println("String is null!");
}
}
}
ArrayIndexOutOfBoundsException:
public class Main {
public static void main(String[] args) {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[5]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Invalid index!");
}
}
}
Multiple catch Blocks
public class Main {
public static void main(String[] args) {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[5]); // May throw ArrayIndexOutOfBoundsException
int result = 10 / 0; // May throw ArithmeticException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Invalid array index");
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero");
} catch (Exception e) {
System.out.println("Some error occurred");
}
System.out.println("Program continues");
}
}
Rule: Specific exceptions before general Exception.
Multi-catch (Java 7+)
Handle multiple exceptions in one catch block.
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0;
} catch (ArithmeticException | NullPointerException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Exception Object Methods
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
// getMessage() - error message
System.out.println("Message: " + e.getMessage());
// toString() - exception type + message
System.out.println("ToString: " + e.toString());
// printStackTrace() - detailed trace
e.printStackTrace();
}
}
}
Nested try-catch
public class Main {
public static void main(String[] args) {
try {
System.out.println("Outer try");
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Inner catch: " + e.getMessage());
}
String str = null;
System.out.println(str.length());
} catch (NullPointerException e) {
System.out.println("Outer catch: " + e.getMessage());
}
}
}
Complete Example: Calculator
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
try {
System.out.print("Enter first number: ");
int num1 = sc.nextInt();
System.out.print("Enter second number: ");
int num2 = sc.nextInt();
System.out.print("Enter operation (+, -, *, /): ");
char op = sc.next().charAt(0);
int result = 0;
switch (op) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2; // May throw ArithmeticException
break;
default:
System.out.println("Invalid operation");
return;
}
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Error: Cannot divide by zero");
} catch (Exception e) {
System.out.println("Error: Invalid input");
} finally {
sc.close();
System.out.println("Calculator closed");
}
}
}
Exception Propagation
Exception moves up the call stack until caught.
class Demo {
void method3() {
int result = 10 / 0; // Exception occurs here
}
void method2() {
method3(); // Exception propagates
}
void method1() {
try {
method2(); // Exception propagates
} catch (ArithmeticException e) {
System.out.println("Exception caught in method1");
}
}
}
public class Main {
public static void main(String[] args) {
Demo d = new Demo();
d.method1();
System.out.println("Program continues");
}
}
Benefits of Exception Handling
- Prevents crash - program continues
- Separates error handling from normal code
- Provides error information
- Maintains program flow
- Cleanup resources properly
try-finally (without catch)
import java.io.*;
public class Main {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("test.txt");
// Read file
} finally {
// Always close file
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Real-World Example: File Reading
import java.io.*;
public class FileReader {
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new java.io.FileReader("data.txt"));
String line;
System.out.println("File contents:");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.out.println("Error: File not found");
} catch (IOException e) {
System.out.println("Error: Cannot read file");
} finally {
try {
if (reader != null) {
reader.close();
System.out.println("File closed");
}
} catch (IOException e) {
System.out.println("Error closing file");
}
}
}
}
Exception Flow
1. Exception occurs in try block
↓
2. Execution stops at that point
↓
3. JVM searches for matching catch
↓
4. If found: execute catch block
If not found: propagate to caller
↓
5. Execute finally block (if present)
↓
6. Continue after try-catch-finally
Common Exceptions
| Exception | Cause |
|---|---|
| ArithmeticException | Division by zero |
| NullPointerException | Using null reference |
| ArrayIndexOutOfBoundsException | Invalid array index |
| NumberFormatException | Invalid string to number |
| FileNotFoundException | File doesn’t exist |
| IOException | I/O operation failed |
| ClassNotFoundException | Class not found |
| IllegalArgumentException | Invalid method argument |
Exception Hierarchy (Brief)
Object
└── Throwable
├── Error (serious, don't catch)
└── Exception
├── RuntimeException (unchecked)
└── Other Exceptions (checked)
Best Practices
- Catch specific exceptions first
- Don’t catch Error class
- Always close resources in finally
- Log exceptions for debugging
- Don’t hide exceptions with empty catch
- Use meaningful error messages
- Clean up resources properly
Common Mistakes
// ✗ Wrong - empty catch block
try {
int result = 10 / 0;
} catch (Exception e) {
// Nothing - bad practice!
}
// ✗ Wrong - general before specific
try {
// code
} catch (Exception e) {
// ...
} catch (ArithmeticException e) { // Error: unreachable
// ...
}
// ✓ Correct - specific first
try {
// code
} catch (ArithmeticException e) {
System.out.println("Arithmetic error");
} catch (Exception e) {
System.out.println("General error");
}
Quick Reference
// Basic try-catch
try {
// risky code
} catch (ExceptionType e) {
// handle
}
// Multiple catch
try {
// risky code
} catch (Exception1 e) {
// handle 1
} catch (Exception2 e) {
// handle 2
}
// Multi-catch (Java 7+)
try {
// risky code
} catch (Exception1 | Exception2 e) {
// handle both
}
// try-catch-finally
try {
// risky code
} catch (Exception e) {
// handle
} finally {
// always runs
}
// Exception methods
e.getMessage() // error message
e.toString() // exception info
e.printStackTrace() // detailed trace
When to Use Exception Handling?
Use for:
- File operations
- Network operations
- Database operations
- User input validation
- Array/collection access
- Type conversions
Don’t use for:
- Normal program logic
- Expected conditions
- Control flow
Exam Tips
Remember:
- try contains risky code
- catch handles exception
- finally always executes
- Specific exceptions before general
- Multiple catch blocks allowed
- Multi-catch with | (Java 7+)
- Exception object has methods
- Propagation up call stack
- Don’t catch Error class
- Always close resources in finally
Common Questions:
- What is exception?
- Purpose of exception handling?
- try-catch syntax?
- Multiple catch blocks?
- Order of catch blocks?
- What is finally block?
- Exception propagation?
- Common exception types?
- Benefits of exception handling?
- Best practices?