TS
JV

TypeScript to Java

10 lessons

Progress0%
1Introduction: Compiler to JVM2Type Systems: Structural vs Nominal3Classes & OOP4Generics5Modules to Packages6Null Safety7Async to Threads8Ecosystem9Exception Handling10Collections and Stream API
All Mirror Courses
TS
JV
Exception Handling
MirrorLesson 9 of 10
Lesson 9

Exception Handling

Java checked vs unchecked exceptions, try-with-resources vs TS try/catch

Introduction

In this lesson, you'll learn about exception handling in Java. Coming from TypeScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
TS
From TypeScript:

In TypeScript, you're familiar with java checked vs unchecked exceptions, try-with-resources vs ts try/catch.

JV
In Java:

Java has its own approach to java checked vs unchecked exceptions, try-with-resources vs ts try/catch, which we'll explore step by step.

The Java Way

Let's see how Java handles this concept. Here's a typical example:

JV
Java Example
import java.io.*;
import java.sql.*;

// Checked exception: MUST handle or declare 'throws'
public String readFile(String path) throws IOException {
    // IOException is checked — callers must handle it
    return Files.readString(Path.of(path));
}

// Unchecked exception: extends RuntimeException, no declaration needed
public class ValidationException extends RuntimeException {
    private final String field;
    ValidationException(String field, String message) {
        super(message);
        this.field = field;
    }
    public String getField() { return field; }
}

// try-with-resources (Java 7+) — auto-closes
// equivalent to TS try/finally with manual close
public void process(String path) throws IOException {
    try (BufferedReader reader = new BufferedReader(new FileReader(path));
         Connection conn = DriverManager.getConnection(dsn)) {
        // reader and conn auto-closed at end of block
        String line = reader.readLine();
        PreparedStatement stmt = conn.prepareStatement("SELECT ?");
        stmt.setString(1, line);
    }
    // IOException propagated to caller
}

// Catching multiple types
try {
    riskyOperation();
} catch (IOException | SQLException e) {    // multi-catch
    logger.error("IO or SQL error: {}", e.getMessage());
} catch (ValidationException e) {          // unchecked
    logger.warn("Validation: {} {}", e.getField(), e.getMessage());
} finally {
    cleanup();
}

Comparing to TypeScript

Here's how you might have written similar code in TypeScript:

TS
TypeScript (What you know)
// TypeScript: all exceptions are unchecked
try {
  const data = await fetchUser(id);
  processData(data);
} catch (e) {
  if (e instanceof NetworkError) {
    console.error("Network:", e.message);
  } else if (e instanceof ValidationError) {
    console.error("Validation:", e.field, e.message);
  } else {
    throw e; // re-throw unknown
  }
} finally {
  releaseResources();
}

// Custom error
class NetworkError extends Error {
  constructor(public statusCode: number, message: string) {
    super(message);
    this.name = "NetworkError";
  }
}

// No concept of "checked" exceptions
async function readFile(path: string): Promise<string> {
  return fs.readFile(path, "utf-8"); // no throws declaration
}
Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

JV
In Java:

Java has checked exceptions (must handle or declare 'throws') — TS has none

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

JV
In Java:

Checked exceptions: IOException, SQLException — extend Exception

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

JV
In Java:

Unchecked exceptions: NullPointerException, ValidationException — extend RuntimeException

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

JV
In Java:

try-with-resources auto-closes Closeable resources (like 'using' in C# or 'with' in Python)

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

JV
In Java:

Multi-catch: catch (IOException | SQLException e) handles multiple types

Step-by-Step Breakdown

1. Checked vs Unchecked

Checked exceptions must be declared with 'throws' or caught. Unchecked (RuntimeException) don't need declaration. This is a Java-unique concept.

TS
TypeScript
// TS: no distinction — all exceptions are unchecked
async function readFile(p: string): Promise<string> {}
JV
Java
// Checked — callers must handle:
public String readFile(String p) throws IOException { ... }
// Unchecked — no declaration needed:
public void validate(int n) { // throws IllegalArgumentException implicitly
    if (n < 0) throw new IllegalArgumentException("negative");
}

2. try-with-resources

Resources implementing Closeable/AutoCloseable are automatically closed when the try block exits, even on exception.

TS
TypeScript
const stream = await openStream(path);
try { ... } finally { await stream.close(); }
JV
Java
try (InputStream in = new FileInputStream(path)) {
    // in.close() called automatically
    byte[] data = in.readAllBytes();
} // in.close() called here

3. Multi-catch

Java 7+ allows catching multiple exception types in one catch block with |. The exception variable is effectively final.

TS
TypeScript
catch (e) {
  if (e instanceof A || e instanceof B) { handle(e); }
}
JV
Java
catch (IOException | SQLException e) {
    logger.error("error: {}", e.getMessage());
    // e is effectively final — cannot reassign
}

4. Wrapping Checked Exceptions

When calling checked APIs from unchecked code, wrap them in RuntimeException. This is common in lambda expressions.

TS
TypeScript
// TS: all exceptions propagate without wrappers
JV
Java
// Wrap IOException in RuntimeException for use in streams
list.stream().map(path -> {
    try { return Files.readString(path); }
    catch (IOException e) { throw new UncheckedIOException(e); }
}).collect(toList());
Rule of Thumb
Prefer unchecked (RuntimeException) for application errors. Use checked only for recoverable external failures like I/O.

Common Mistakes

When coming from TypeScript, developers often make these mistakes:

  • Java has checked exceptions (must handle or declare 'throws') — TS has none
  • Checked exceptions: IOException, SQLException — extend Exception
  • Unchecked exceptions: NullPointerException, ValidationException — extend RuntimeException
Common Pitfall
Don't assume Java works exactly like TypeScript. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • Checked exceptions (IOException etc.) must be declared with 'throws' or caught
  • Unchecked exceptions (RuntimeException subclasses) need no declaration
  • try-with-resources auto-closes any AutoCloseable resource
  • Multi-catch: catch (A | B e) handles multiple exception types in one block
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your TypeScript code in Java to practice these concepts.
PreviousNext