Exceptions ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-10-28

Java Exceptions and Exception Handling

One line is enough: int a = 10 / d; with d = 0 — and the program crashes before reaching the next statement. The JVM prints java.lang.ArithmeticException: / by zero along with the chain of method calls that led there. Exception handling lets you catch a situation like this and decide what to do next instead of letting the program die.

An exception in Java is an object that describes an exceptional situation that occurred while a program was running: an integer division by zero, a method call on null, a missing file, a badly formatted number. Exception handling in Java is the mechanism that carries this object from the place where the problem happened to the code that can react to it, using the keywords try, catch, finally, throw and throws.

What is an exception in Java

An exception in Java is an object of a subclass of Throwable that is created at the moment of a runtime failure and stores its type, a message and the stack trace. If nobody catches the exception, the JVM prints this information to the console and terminates the thread in which the exception occurred.

For example, running the following code throws an exception because of division by zero:

public class ExceptionExample1 {
    public static void main(String[] args) {
        subRoutine();
    }

    public static void subRoutine() {
        int d = 0;
        int a = 10 / d;
    }
}

Output:

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at ExceptionExample1.subRoutine(ExceptionExample1.java:8)
	at ExceptionExample1.main(ExceptionExample1.java:3)

This is a stack trace, and you read it from top to bottom: the first line shows the exception type and message, the second shows where it happened (method subRoutine, line 8), and the lines below show who called that method. In practice, the cause of a bug is usually found in the topmost at ... line that points to your own code.

Compile errors are not exceptions

A missing semicolon or incompatible types are detected by the javac compiler, and the program simply never starts. Exceptions occur only while already compiled code is running, so try-catch cannot protect you from compilation errors.

How exception handling works

When an exception occurs in a method, that method stops executing, and the JVM looks for a matching catch block first in the current method, then in its caller, and so on up the call stack. The first matching handler receives the exception object, and the program continues right after that handler.

Let us add a handler to the main method of the previous example:

public class ExceptionExample2 {
    public static void main(String[] args) {
        try {
            subRoutine();
            System.out.println("This line will not run");
        } catch (ArithmeticException e) {
            System.out.println("Caught: " + e.getMessage());
        }
        System.out.println("The program keeps running");
    }

    public static void subRoutine() {
        int d = 0;
        int a = 10 / d;
        System.out.println("Neither will this one");
    }
}

Output:

Caught: / by zero
The program keeps running

Note that the exception was thrown in subRoutine() but handled in main(): the method where the failure happens can handle the exception itself or let it propagate further. Both lines after the failure point were skipped — execution never returns to the place where the exception was thrown; it continues after the try-catch statement.

If no method in the call stack has a matching catch block, the default handler takes over: it prints the stack trace, as in the first example, and terminates the thread. The try-catch-finally syntax, the order of multiple catch blocks and multi-catch are covered in the lesson Java Try Catch Finally.

Types of exceptions: a short hierarchy

All Java exceptions inherit from the Throwable class, which has two branches: Error for serious JVM-level failures and Exception for situations a program can handle. Inside Exception, the RuntimeException subclass decides whether the compiler forces you to handle the exception: checked vs unchecked.

Branch Examples Kind Does the compiler require handling?
Error OutOfMemoryError, StackOverflowError Unchecked No; usually not caught at all
Exception (except RuntimeException) IOException, SQLException, ParseException Checked Yes: catch it or declare it in throws, otherwise a compile-time error
RuntimeException and its subclasses ArithmeticException, NullPointerException, NumberFormatException Unchecked No; these usually signal bugs in program logic

The full Java exception hierarchy diagram, examples of each kind and the methods of the Throwable class (getMessage(), printStackTrace() and others) are covered in a separate lesson of this module.

Exception handling keywords: module map

Exception handling in Java is built on five keywords: try marks risky code, catch catches an exception, finally runs cleanup code, throw throws an exception, and throws declares it in a method signature. Each of them has its own lesson in this module.

Construct Where it goes What it does Details
try A block in a method body Marks code that may throw an exception Try catch finally syntax
catch After try Catches an exception of the given type and its subclasses Order of catch blocks
finally After try/catch Runs whatever the outcome, usually to release resources The finally block
try (resource) The try header Try-with-resources: closes AutoCloseable resources automatically Try-with-resources
throw A statement in a method body Throws a specific exception object Covered in a separate lesson of this module
throws Method signature Declares checked exceptions that the method does not handle itself Covered in a separate lesson of this module
extends Exception Class declaration Creates your own exception type Covered in a separate lesson of this module
throws when overriding Subclass method or constructor Restricts which checked exceptions an overriding method may declare Covered in a separate lesson of this module

Who throws exceptions: the JVM or your program

Java exceptions are generated in two ways: automatically by the Java runtime when a language rule is broken (integer division by zero, an array index out of bounds, a method call on null), and manually in application code with the throw statement, when the program itself detects an invalid situation.

  • The JVM throws ArithmeticException, ArrayIndexOutOfBoundsException, NullPointerException, ClassCastException and others — without a single line of code on your side.
  • JDK libraries are a special case of the second way, the same throw inside standard classes: for example, Integer.parseInt("abc") throws NumberFormatException, and reading a missing file throws NoSuchFileException or FileNotFoundException (both subclasses of IOException).
  • Your code throws an exception when data is invalid from the business logic point of view: throw new IllegalArgumentException("Age cannot be negative"). For such cases you can also create your own exception class.

Mistakes beginners make with exceptions

The most dangerous mistake in exception handling is to swallow an exception: catch it and report nothing. The program keeps working with wrong data, and later the cause of the failure has to be hunted down blindly. What does this code print?

public class SwallowedException {
    static int parseAge(String input) {
        try {
            return Integer.parseInt(input);
        } catch (NumberFormatException e) {
            return 0; // bad: the error is swallowed
        }
    }

    public static void main(String[] args) {
        System.out.println(parseAge("25"));  // Output: 25
        System.out.println(parseAge("abc")); // Output: 0
    }
}

For the string "abc" the method silently returned 0 — and further down the code the user becomes a newborn. The fix: if a method cannot handle an error in a meaningful way, it should report it to the caller and keep the original cause:

static int parseAge(String input) {
    try {
        return Integer.parseInt(input);
    } catch (NumberFormatException e) {
        throw new IllegalArgumentException("Invalid age: " + input, e);
    }
}

Output for parseAge("abc") (fragment):

Exception in thread "main" java.lang.IllegalArgumentException: Invalid age: abc
	at SwallowedException.parseAge(...)
	...
Caused by: java.lang.NumberFormatException: For input string: "abc"

Other common mistakes:

  • catch (Exception e) just in case — it catches expected failures and bugs like NullPointerException alike, although bugs are better seen and fixed. Catch the most specific type.
  • Exceptions instead of checks — catching ArrayIndexOutOfBoundsException instead of checking i < array.length is slower and harder to read. Exceptions are for exceptional situations, not for regular branching.
  • Losing the cause — throw new MyException("failed") inside catch without passing e breaks the Caused by chain, and the original stack trace is lost.

Frequently Asked Questions

What does e mean in catch (Exception e) in Java?

e is the parameter of the catch block, a reference to the caught exception object. The name can be anything; e is just a convention. Through it you get the message with e.getMessage(), the cause with e.getCause(), or print the stack trace with e.printStackTrace(). The type in parentheses defines which exceptions the block catches: catch (Exception e) catches any Exception, including RuntimeException, but not Error.

What is IOException in Java?

IOException from the java.io package is a checked exception that signals an input/output failure: a file is not found, access is denied, a network connection is dropped. The compiler requires you either to catch it in catch or to declare it in the throws clause of the method. Its place among other exception classes is shown in the section Types of exceptions.

Can execution resume at the line where the exception occurred?

No. Java has no resumption mechanism: after the exception is caught, execution continues after the try-catch statement, and the remaining lines of the try block and of all interrupted methods are skipped. If an operation must be retried, wrap the try in a loop. An example with output is in the section How exception handling works.

How do I create a custom exception in Java?

Declare a subclass: extends Exception for a checked exception that the calling code must handle, or extends RuntimeException for an unchecked one. Usually a constructor that passes the message and the cause to super(message, cause) is enough, so the Caused by chain is preserved.

Comments

Please log in or register to have a possibility to add comment.