Error Handling in Java: try/catch and Beyond — from A to Z
Error handling is one of the key concepts in Java that every developer must master. Unlike many languages, Java offers a strict and well-thought-out exception system that allows you to write reliable and predictable code. In this article, we will cover everything: from the basic try/catch to advanced mechanisms such as try-with-resources and custom exceptions.
1. Basics: what are exceptions and the class hierarchy
An exception is an event that disrupts the normal flow of program execution. In Java, all exceptions are objects of classes that inherit from Throwable. The main branches of the hierarchy are:
- Error — critical problems that are typically not handled (e.g.,
OutOfMemoryError). - Exception — exceptions that the program can handle.
- RuntimeException (a subclass of Exception) — runtime exceptions that do not need to be checked at compile time.
All exceptions are divided into two types:
- Checked — must be handled. The compiler will not compile the code if you do not handle them with
try/catchor declare them withthrows. Examples:IOException,SQLException. - Unchecked — inherit from
RuntimeException. They do not need to be explicitly handled. Examples:NullPointerException,ArithmeticException.
2. The main mechanism: try, catch, finally
The basic exception handling block consists of three parts:
try { // Code that may throw an exception int result = 10 / 0;} catch (ArithmeticException e) { // Exception handling System.err.println("Error: division by zero!");} finally { // This block always executes (even if an exception occurred) System.out.println("Finally block executed.");}Important points:
- The
catchblock can be one or several for different exception types. - The
finallyblock is optional but useful for closing resources (files, connections). - If an exception is not caught, it propagates up the call stack.
Multi-catch (Java 7+) — allows catching multiple exception types in one block:
try { // code} catch (IOException | SQLException e) { System.err.println("I/O or SQL error: " + e.getMessage());}3. Try-with-resources: automatic resource closing
Starting from Java 7, the try-with-resources mechanism was introduced, which automatically closes resources that implement the AutoCloseable (or Closeable) interface. This eliminates the need to write finally for closing files, sockets, etc.
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) { String line = reader.readLine(); System.out.println(line);} catch (IOException e) { System.err.println("File reading error: " + e.getMessage());} // reader is closed automaticallyAdvantages:
- Code becomes cleaner and shorter.
- Resources are closed in the correct order (reverse order of their creation).
- If an exception is thrown both in the try block and during closing, the suppressed exception is added to the main one.
You can declare multiple resources separated by a semicolon:
try (BufferedReader br = new BufferedReader(new FileReader("in.txt")); BufferedWriter bw = new BufferedWrite