Lesson 137 min read

Exception Handling

Catch problems before they crash your program

What Are Exceptions?

Imagine you're following a recipe and it says "add 2 eggs." But the carton is empty. You can either panic and burn down the kitchen (crash), or handle it gracefully — maybe skip the eggs or run to the store. That's what exception handling does for your code.

An exception is Java's way of saying "something unexpected happened." When one is thrown, Java unwinds the call stack looking for a handler. Without handling, your program crashes with a scary red error message. With proper handling, you catch the problem and deal with it.

Java has two main categories:

  • Checked exceptions — Java forces you to handle these (like IOException). The compiler won't let your code run without a try/catch or throws declaration.
  • Unchecked exceptions — runtime problems Java doesn't force you to handle (like NullPointerException, ArrayIndexOutOfBoundsException). These are usually bugs in your code.

Try / Catch / Finally

public class Main {
public static void main(String[] args) {
// Basic try-catch
try {
int result = 10 / 0; // this will throw ArithmeticException
System.out.println("Result: " + result); // never reached
} catch (ArithmeticException e) {
System.out.println("Oops! Can't divide by zero.");
System.out.println("Error: " + e.getMessage());
}
System.out.println("---");
// Multiple catch blocks
String[] names = {"Alice", "Bob"};
try {
System.out.println(names[5]); // out of bounds!
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("That index doesn't exist!");
} catch (Exception e) {
System.out.println("Something else went wrong.");
}
System.out.println("---");
// Finally — runs NO MATTER WHAT
try {
int x = Integer.parseInt("abc"); // NumberFormatException
} catch (NumberFormatException e) {
System.out.println("That's not a number!");
} finally {
System.out.println("Finally block always runs.");
}
System.out.println("Program continues normally!");
}
}
Output
Oops! Can't divide by zero.
Error: / by zero
---
That index doesn't exist!
---
That's not a number!
Finally block always runs.
Program continues normally!

Throwing Exceptions & Custom Exceptions

Sometimes you want to be the one throwing an exception. Maybe someone passes a negative age to your method — that doesn't make sense, so you throw an exception to signal the problem.

Use throw new ExceptionType("message") to throw an exception. Use throws in the method signature to warn callers that this method might throw a checked exception.

You can also create your own custom exception classes by extending Exception (checked) or RuntimeException (unchecked).

Throw, Throws & Custom Exceptions

public class Main {
// Custom exception
static class InvalidAgeException extends Exception {
InvalidAgeException(String message) {
super(message);
}
}
// Method that throws our custom exception
static void setAge(String name, int age) throws InvalidAgeException {
if (age < 0) {
throw new InvalidAgeException("Age can't be negative: " + age);
}
if (age > 150) {
throw new InvalidAgeException("Age seems unrealistic: " + age);
}
System.out.println(name + "'s age set to " + age);
}
// Method that throws a built-in exception
static double divide(double a, double b) {
if (b == 0) {
throw new IllegalArgumentException("Cannot divide by zero!");
}
return a / b;
}
public static void main(String[] args) {
// Handle custom exception
try {
setAge("Alice", 25);
setAge("Bob", -5);
} catch (InvalidAgeException e) {
System.out.println("Error: " + e.getMessage());
}
System.out.println("---");
// Handle built-in exception
try {
System.out.println("10 / 3 = " + divide(10, 3));
System.out.println("10 / 0 = " + divide(10, 0));
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output
Alice's age set to 25
Error: Age can't be negative: -5
---
10 / 3 = 3.3333333333333335
Error: Cannot divide by zero!

Try-With-Resources

import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// Try-with-resources automatically closes resources
// Even if an exception occurs!
String data = "42\n3.14\nhello\n100";
try (Scanner scanner = new Scanner(data)) {
while (scanner.hasNext()) {
String token = scanner.next();
try {
int num = Integer.parseInt(token);
System.out.println("Integer: " + num);
} catch (NumberFormatException e1) {
try {
double d = Double.parseDouble(token);
System.out.println("Double: " + d);
} catch (NumberFormatException e2) {
System.out.println("String: " + token);
}
}
}
} // scanner is automatically closed here!
System.out.println("Scanner was auto-closed. Clean!");
}
}
Output
Integer: 42
Double: 3.14
String: hello
Integer: 100
Scanner was auto-closed. Clean!
Note: Golden rule: catch specific exceptions, not generic ones. Writing catch (Exception e) is like a doctor saying "you're sick" without telling you what's wrong. Catch NumberFormatException, IOException, etc. so you can handle each problem appropriately. Use generic Exception only as a last-resort safety net.

Quick check

What is the difference between checked and unchecked exceptions?

Continue reading

StackData Structure
LIFO — array & linked-list backed
Error HandlingPython
Catch mistakes before they crash your program
Error HandlingJavascript
try/catch and throwing your own errors
GenericsFile I/O