Exception Handling in Java – Complete Guide with Examples
An exception is an unexpected event that interrupts the normal flow of a program: dividing by zero, opening a file that does not exist, reading text where a number was expected, or losing a network connection. Exception handling is how Java lets you detect these problems, respond to them, and keep the program running or fail gracefully.
This guide introduces the whole topic: what happens when an exception is not handled, the exception class hierarchy, the five keywords (try, catch, finally, throw, throws), how exceptions travel up the call stack, and the best practices professionals follow. Each part links to a detailed tutorial.
1. What Happens Without Exception Handling
When an exception is thrown and nothing catches it, the JVM stops the thread and prints the exception and a stack trace:
public class WithoutHandling {
public static void main(String[] args) {
System.out.println("Calculating average...");
int total = 250, count = 0;
int average = total / count; // ArithmeticException: nobody handles it
System.out.println("Average: " + average); // never runs
}
}
Calculating average... Exception in thread "main" java.lang.ArithmeticException: / by zero at WithoutHandling.main(WithoutHandling.java:5)
The last println never ran. The stack trace tells you exactly what went wrong (ArithmeticException: / by zero) and where (WithoutHandling.java, line 5). Reading stack traces is one of the most useful debugging skills in Java.
2. Handling the Exception with try-catch
Put risky code in a try block and the recovery code in a catch block. A finally block runs whether or not an exception occurred:
public class WithHandling {
public static void main(String[] args) {
System.out.println("Calculating average...");
int total = 250, count = 0;
try {
int average = total / count;
System.out.println("Average: " + average);
} catch (ArithmeticException e) {
System.out.println("Cannot calculate: no items (" + e.getMessage() + ")");
} finally {
System.out.println("Calculation finished");
}
System.out.println("The program continues normally.");
}
}
Calculating average... Cannot calculate: no items (/ by zero) Calculation finished The program continues normally.
This time the program reported a clear message and carried on. See try-catch block and finally block.
3. The Exception Hierarchy
Throwable
├─ Error serious JVM problems: OutOfMemoryError, StackOverflowError
└─ Exception problems a program can handle
├─ IOException, SQLException, ... checked exceptions
└─ RuntimeException unchecked exceptions
├─ NullPointerException
├─ ArithmeticException
├─ IllegalArgumentException → NumberFormatException
└─ IndexOutOfBoundsException → ArrayIndexOutOfBoundsException
- Errors signal problems you usually cannot recover from. See Error vs Exception.
- Checked exceptions must be caught or declared; the compiler enforces it.
- Unchecked exceptions (
RuntimeExceptionand its subclasses) usually signal programming bugs and need not be declared. See Checked vs Unchecked.
4. The Five Exception Keywords
| Keyword | Purpose | Tutorial |
|---|---|---|
try | Wraps code that might throw an exception | try-catch |
catch | Handles a specific type of exception | multiple catch |
finally | Runs clean-up code in every case | finally |
throw | Throws an exception object | throw |
throws | Declares exceptions a method may throw | throws |
Related features: try-with-resources closes files and connections automatically, nested try blocks handle errors at several levels, and custom exceptions describe problems specific to your application.
5. How Exceptions Propagate
If a method does not catch an exception, it ends immediately and the exception passes to its caller, then to that caller's caller, and so on up the call stack, until some method catches it or it reaches the top and stops the thread:
public class Propagation {
static int parseAge(String text) {
return Integer.parseInt(text); // may throw NumberFormatException
}
static String register(String name, String ageText) {
int age = parseAge(ageText); // not caught here: passes upward
return name + " registered, age " + age;
}
public static void main(String[] args) {
String[][] inputs = {{"Asha", "28"}, {"Ravi", "twenty"}};
for (String[] in : inputs) {
try {
System.out.println(register(in[0], in[1]));
} catch (NumberFormatException e) { // caught two levels up
System.out.println("Could not register " + in[0] + ": " + e.getMessage());
}
}
}
}
Asha registered, age 28 Could not register Ravi: For input string: "twenty"
Neither parseAge() nor register() handles the error; main() catches it where it can decide what to do. Catching exceptions at the level that knows how to respond is a key design principle.
6. Getting Information from an Exception
public class ExceptionInfo {
static void loadUser(String id) {
if (id.isBlank()) throw new IllegalArgumentException("user id must not be blank");
}
public static void main(String[] args) {
try {
loadUser(" ");
} catch (IllegalArgumentException e) {
System.out.println("getMessage(): " + e.getMessage());
System.out.println("toString(): " + e);
System.out.println("class name: " + e.getClass().getName());
System.out.println("thrown in: " + e.getStackTrace()[0].getMethodName() + "()");
System.out.println("stack trace:");
e.printStackTrace(System.out);
}
}
}
getMessage(): user id must not be blank toString(): java.lang.IllegalArgumentException: user id must not be blank class name: java.lang.IllegalArgumentException thrown in: loadUser() stack trace: java.lang.IllegalArgumentException: user id must not be blank at ExceptionInfo.loadUser(ExceptionInfo.java:3) at ExceptionInfo.main(ExceptionInfo.java:8)
Every exception carries a message, its type and the stack trace of where it was created. Exceptions can also wrap a cause (getCause()), the original exception that led to this one.
7. Common Built-in Exceptions
| Exception | Typical cause |
|---|---|
NullPointerException | Calling a method on a null reference |
ArithmeticException | Integer division by zero |
ArrayIndexOutOfBoundsException | Invalid array index |
NumberFormatException | Parsing text that is not a number |
ClassCastException | Casting an object to an incompatible type |
IllegalArgumentException | Invalid method argument |
IllegalStateException | Method called at the wrong time |
IOException / FileNotFoundException | File or stream problems (checked) |
InterruptedException | A waiting thread was interrupted (checked) |
More in Types of Exception in Java.
8. Best Practices
- Catch specific exceptions, not
ExceptionorThrowable, unless you are at the top level of an application. - Never swallow exceptions with an empty
catch; at least log them. - Fail fast: validate inputs and throw clear exceptions early.
- Use try-with-resources for anything that must be closed.
- Keep the cause when wrapping:
throw new ServiceException("Order failed", e);. - Do not use exceptions for normal control flow; they are for exceptional situations.
- Prefer avoiding exceptions where a simple check works, for example testing for
nullor usingOptional.
9. Summary
- An exception is an event that disrupts normal execution; unhandled, it stops the thread with a stack trace.
- All exceptions descend from
Throwable, split intoErrorandException;RuntimeExceptionsubclasses are unchecked. try,catch,finally,throwandthrowsare the core tools.- Uncaught exceptions propagate up the call stack until handled.
- Handle exceptions where you can respond meaningfully, and never hide them.
Reference: dev.java: Exceptions
Frequently Asked Questions (FAQ)
Q1. What is an exception in Java?
An object representing an unexpected event, such as an invalid operation or a missing file, that interrupts the normal flow of a program. It is an instance of Throwable or one of its subclasses.
Q2. What is exception handling?
The mechanism for detecting and responding to exceptions using try, catch and finally, so the program can recover, report a clear message or clean up instead of crashing.
Q3. What is the root class of all exceptions?
java.lang.Throwable. Its two direct subclasses are Error and Exception.
Q4. What is the difference between checked and unchecked exceptions?
Checked exceptions (subclasses of Exception but not RuntimeException) must be caught or declared with throws. Unchecked exceptions (RuntimeException and Error subclasses) do not have to be.
Q5. What happens if an exception is not caught?
It propagates up the call stack. If no method catches it, the thread terminates and the JVM prints the exception and its stack trace. If it is the main thread and no other non-daemon threads are running, the program ends.
Q6. What is a stack trace?
A list of the method calls that were active when the exception was created, from the innermost to the outermost, with file names and line numbers. It shows where the problem happened and how the program got there.
Q7. What is the difference between Error and Exception?
Error represents serious problems in the JVM or environment, such as running out of memory, which applications normally should not catch. Exception represents conditions a program can reasonably handle.
Q8. Can a try block exist without a catch block?
Yes, if it has a finally block (try-finally) or is a try-with-resources statement.
Q9. Does finally always run?
Almost always: after normal completion, after an exception, and after return, break or continue. It does not run if the JVM exits (System.exit()) or crashes.
Q10. What is the difference between throw and throws?
throw actually throws an exception object inside a method. throws appears in a method's declaration to list exceptions it may throw.
Q11. Should I catch Exception or specific exceptions?
Catch specific exceptions you can handle. Catching Exception broadly can hide bugs; it is acceptable only at top-level boundaries such as a request handler that logs and reports errors.
Q12. What is exception propagation?
The process by which an uncaught exception leaves a method and is passed to its caller, continuing up the call stack until it is caught.
Q13. What is exception chaining?
Wrapping one exception inside another as its cause, for example throw new DataException("Load failed", e);. The original exception remains available through getCause() and appears in the stack trace.
Q14. Is it bad to catch NullPointerException?
Usually yes. A NullPointerException indicates a bug that should be fixed by checking for null or avoiding null values, not hidden by a catch block.
Q15. Do exceptions affect performance?
Creating an exception and capturing its stack trace is relatively expensive, so do not use exceptions for normal control flow. A try block that does not throw has practically no cost.
Q16. What is a custom exception?
An exception class you define by extending Exception or RuntimeException, to describe errors specific to your application, such as InsufficientBalanceException.
Q17. What does printStackTrace() do?
It prints the exception and its stack trace, by default to the standard error stream. In real applications, log exceptions with a logging framework instead.
Q18. Can a catch block throw an exception?
Yes. A catch block can rethrow the same exception or throw a new one, often wrapping the original as its cause.
Q19. What is the helpful NullPointerException message?
Since Java 14, NPE messages describe exactly what was null, for example Cannot invoke "String.length()" because "name" is null, which makes debugging much easier.
Q20. Why does Java have checked exceptions?
To force callers to think about recoverable failures, such as I/O problems, at compile time. Many modern libraries prefer unchecked exceptions, but checked exceptions remain part of core Java APIs.