Catch and handle errors with try/catch/finally, clean up resources automatically, throw your own exceptions, and know checked from unchecked.
Why: an exception is Java's way of signalling that something went wrong at runtime. Wrap risky code in try; if it throws, control jumps to the matching catch block instead of crashing the program.
try {
int result = 10 / 0; // throws ArithmeticException
System.out.println(result); // skipped
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero: " + e.getMessage());
}
System.out.println("program keeps running");Why: different problems throw different exception types. You can have several catch blocks, or combine related ones with a | . Order matters — list more specific types before more general ones.
String[] data = { "10", "oops" };
try {
int n = Integer.parseInt(data[2]); // out of bounds
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
System.out.println("Bad input: " + e);
}Why: the finally block runs no matter what — whether the try succeeded, threw, or returned. It is the place for cleanup that must always happen, like closing a file or releasing a lock.
try {
System.out.println("doing work");
throw new RuntimeException("boom");
} catch (RuntimeException e) {
System.out.println("caught: " + e.getMessage());
} finally {
System.out.println("always runs — cleanup here");
}Why: anything that must be closed (files, database connections) should be opened in a try-with-resources. You declare it in parentheses and Java closes it automatically when the block ends — even if an error is thrown. No finally needed.
import java.io.BufferedReader;
import java.io.FileReader;
try (BufferedReader reader = new BufferedReader(new FileReader("notes.txt"))) {
System.out.println(reader.readLine());
} catch (Exception e) {
System.out.println("could not read file");
}
// reader is closed automatically hereWhy: when your code detects something invalid, throw an exception to stop and signal the problem. IllegalArgumentException is the standard choice for bad arguments. The caller can then catch and handle it.
void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("age cannot be negative: " + age);
}
System.out.println("age set to " + age);
}
// setAge(-5); // throws, with a clear messageWhy: checked exceptions (like IOException) must be either caught or declared with "throws" on the method — the compiler enforces it, usually for outside-world failures. Unchecked exceptions (RuntimeException and its kin, like NullPointerException) are programming bugs and need no declaration.
import java.io.IOException;
// checked: the compiler forces you to declare or catch it
void readConfig() throws IOException {
throw new IOException("file missing");
}
// unchecked: no "throws" needed — these signal bugs to fix
void brokenLogic() {
throw new IllegalStateException("should never happen");
}