JSTAcademy
0 XP
Dashboard
Crash Courses
Exception Handling & File I/O
20 min
PhD+185 XP
Crash Courses · PhD

Exception Handling & File I/O

Write robust exception handling with try/catch/finally, define custom exceptions, and read/write files with modern Java NIO.
20 min read+185 XP on completionCert: Java / Kotlin Crash Course
Tap any word in the text below to start reading from there.

Exception Handling & File I/O

The Exception Hierarchy

Throwable
├── Error  (JVM-level — OutOfMemoryError — don't catch these)
└── Exception
    ├── Checked Exceptions (must handle at compile time)
    │   ├── IOException
    │   ├── SQLException
    │   └── ParseException
    └── RuntimeException (unchecked — handle if you want)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        ├── IllegalArgumentException
        └── NumberFormatException

---

try / catch / finally

public static int divide(int a, int b) {
    try {
        return a / b;
    } catch (ArithmeticException e) {
        System.err.println("Division by zero: " + e.getMessage());
        return 0;
    } finally {
        System.out.println("divide() completed"); // always runs
    }
}

// Multiple catch blocks — most specific first:
public static int parseAndDouble(String input) {
    try {
        int n = Integer.parseInt(input);
        return n * 2;
    } catch (NumberFormatException e) {
        System.err.println("Not a number: " + input);
        return -1;
    } catch (Exception e) {
        System.err.println("Unexpected: " + e.getMessage());
        return -1;
    }
}

// Multi-catch (Java 7+):
try {
    // ...
} catch (IOException | SQLException e) {
    System.err.println("IO or DB error: " + e.getMessage());
}

---

Custom Exceptions

// Checked custom exception
public class InsufficientFundsException extends Exception {
    private final double requested;
    private final double available;

    public InsufficientFundsException(double requested, double available) {
        super(String.format("Requested $%.2f but only $%.2f available",
              requested, available));
        this.requested = requested;
        this.available = available;
    }

    public double getShortfall() { return requested - available; }
}

// Using it:
public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException(amount, balance);
    }
    balance -= amount;
}

// Caller must handle:
try {
    account.withdraw(5000.0);
} catch (InsufficientFundsException e) {
    System.err.println(e.getMessage());
    System.out.printf("You need $%.2f more.%n", e.getShortfall());
}

---

File I/O with java.nio.file

Modern Java uses Path and Files from java.nio.file:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

// Writing a file:
public static void writeReport(String filepath, String content) throws IOException {
    Path path = Paths.get(filepath);
    Files.writeString(path, content);
    System.out.println("Written to: " + path.toAbsolutePath());
}

// Reading a file:
public static List<String> readLines(String filepath) throws IOException {
    return Files.readAllLines(Paths.get(filepath));
}

// Streaming lines (memory-efficient for large files):
public static long countWords(String filepath) throws IOException {
    try (var lines = Files.lines(Paths.get(filepath))) {
        return lines
            .flatMap(line -> java.util.Arrays.stream(line.split("\\s+")))
            .filter(word -> !word.isBlank())
            .count();
    }
}

---

try-with-resources

The safest way to work with resources (files, database connections, network streams):

import java.io.*;
import java.nio.file.*;

// try-with-resources ensures reader.close() is ALWAYS called
public static void processCSV(String filepath) throws IOException {
    try (BufferedReader reader = Files.newBufferedReader(Paths.get(filepath))) {
        String line;
        int lineNum = 0;
        while ((line = reader.readLine()) != null) {
            lineNum++;
            String[] parts = line.split(",");
            if (parts.length < 3) continue;
            System.out.printf("Line %d: name=%s, score=%s%n",
                lineNum, parts[0].trim(), parts[2].trim());
        }
    }
    // reader is automatically closed here — no finally block needed
}

// Writing CSV:
public static void writeCSV(String filepath, List<String[]> rows) throws IOException {
    try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(Paths.get(filepath)))) {
        writer.println("name,email,score");
        for (String[] row : rows) {
            writer.println(String.join(",", row));
        }
    }
}

---

Exception Design Guidelines

  1. Throw early, catch late — validate inputs immediately; handle exceptions at the layer that can do something meaningful
  2. Never swallow exceptions — catch (Exception e) {} hides bugs; at minimum log the error
  3. Use checked exceptions for conditions the caller can reasonably recover from (file not found → prompt for different path)
  4. Use unchecked exceptions for programming errors (invalid argument, null where not expected)
  5. Include context in exception messages — "File not found: " + filepath is better than "File not found"
0%