Skillversitas

Exception Handling

An exception is an unexpected event that disrupts the normal flow of a program. Java uses the try-catch-finally mechanism to handle exceptions. Checked exceptions (which must be handled or declared) differ from unchecked exceptions (runtime exceptions) that are optional to handle.

The Java exception hierarchy: Throwable → Error (system errors, do not handle) and Exception → Checked Exception (IOException, etc.) and RuntimeException (NullPointerException, ArrayIndexOutOfBoundsException, etc.).

Java 7+ supports multi-catch blocks in a single statement. Try-with-resources (Java 7+) automatically closes resources that implement AutoCloseable. Text blocks and switch expressions (Java 14+) also support yield for displaying error messages more elegantly.

Types of Exceptions:

Category Examples Must Handle?
Checked IOException, SQLException Yes (try-catch or throws)
Unchecked NullPointerException, IllegalArgumentException Optional
Error OutOfMemoryError, StackOverflowError No (fatal)

Code Example

import java.io.*;
import java.util.Scanner;

public class PenangananEksepsi {

    // Checked exceptions must be declared
    static int bagi(int a, int b) throws ArithmeticException {
        if (b == 0) throw new ArithmeticException("Cannot divide by zero!");
        return a / b;
    }

    public static void main(String[] args) {
        // Try-catch-finally
        Scanner sc = new Scanner(System.in);
        try {
            System.out.print("Enter numerator: ");
            int a = sc.nextInt();
            System.out.print("Enter denominator: ");
            int b = sc.nextInt();
            int result = bagi(a, b);
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.err.println("Error aritmatika: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("Error umum: " + e.getMessage());
        } finally {
            System.out.println("Program done.");
            sc.close();
        }

        // Multi-catch (Java 7+)
        try {
            String[] arr = {"a", "b"};
            System.out.println(arr[5]);
        } catch (ArrayIndexOutOfBoundsException | NullPointerException e) {
            System.err.println("Array error: " + e.getMessage());
        }

        // Try-with-resources (Java 7+)
        try (BufferedReader br = new BufferedReader(
                new FileReader("data.txt"))) {
            String line = br.readLine();
            System.out.println(line);
        } catch (FileNotFoundException e) {
            System.err.println("File not found");
        } catch (IOException e) {
            System.err.println("Read failed: " + e.getMessage());
        }
    }
}

Code Explanation

  1. Throw: throw new ArithmeticException(...) manually throws an exception with an error message.
  2. Throws: throws ArithmeticException in a method signature tells the caller that this method can throw an exception.
  3. Multi-catch: catch (A | B e) handles two exception types in a single block — efficient when the handling is the same.
  4. Try-with-resources: resources inside try(...) are closed automatically after the block finishes, even if an exception occurs — no manual finally needed.
  5. Finally: always runs regardless of exceptions — suitable for cleanup such as closing a scanner or a connection.

Everyday Example

A configuration file reader program with robust error handling:

import java.nio.file.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class ConfigLoader {
    public static void main(String[] args) {
        Map<String, String> config = loadConfig("config.txt");
        if (config.isEmpty()) {
            System.out.println("Using default config");
        } else {
            System.out.println("Config loaded: " + config);
        }
    }

    static Map<String, String> loadConfig(String filename) {
        Map<String, String> config = new HashMap<>();
        try {
            var path = Path.of(filename);
            if (!Files.exists(path)) {
                System.out.println("File " + filename + " not found");
                return config;
            }
            for (String line : Files.readAllLines(path)) {
                if (line.isBlank() || line.startsWith("#")) continue;
                String[] part = line.split("=", 2);
                if (part.length == 2) {
                    config.put(part[0].trim(), part[1].trim());
                }
            }
        } catch (IOException e) {
            System.err.println("Failed to read config: " + e.getMessage());
        }
        return config;
    }
}

Summary

Good exception handling is what separates robust programs from error-prone ones. Use try-with-resources for resource management, multi-catch for compact handling, and always provide informative error messages. Never handle Errors (OutOfMemoryError, etc.) — those are system issues, not program issues.