Day 21 / 25 Java Exceptions, File I/O & JUnit 0/0 exercises Exercises ↓

AmouAI Hub/Courses/Programming Fundamentals/Day 21

Week 5 · Craft, Comparison & Capstone · Day 21

Java Exceptions, File I/O & JUnit

Checked exceptions are Java's most distinctive design choice. Plus files, and test-driven development demonstrated live.

Study time
4 hours
Reading
Head First Java, Ch. 10, 13
Focus
checked exceptions · TDD

By the end of today you can

  1. Tell a checked exception from an unchecked one, and say why the split exists
  2. Choose between handling an exception and declaring throws
  3. Use try-with-resources, and say what it guarantees
  4. Write a custom exception and decide which kind it should be
  5. Write and run a JUnit 5 test
  6. Assert that something throws, with assertThrows
  7. Work red-green-refactor, and say why the order matters

Today's videos

Watch each video, then work the matching sections below. Watching alone will not do it.

21A
Checked Exceptions & Files (120 min)
The two kinds of exception and what the compiler demands · handle here or declare throws · why the feature is genuinely argued about · try-with-resources as Java's with · the modern java.nio.file API.
21B
JUnit 5 & Test-Driven Development (120 min)
@Test and the assertions worth knowing · assertEquals with a tolerance · assertThrows and why it needs a lambda · red, green, refactor · why watching the test fail first is not ceremony.

1Checked versus unchecked

The design choice no other mainstream language copied.

Python has one kind of exception. Java has two, and the compiler treats them completely differently.

CheckedUnchecked
ExtendsExceptionRuntimeException
Compiler demandsYou handle it or declare itNothing
MeansSomething outside your control failedA bug in the code
ExamplesIOException, FileNotFoundExceptionNullPointerException, IllegalArgumentException
Python equivalentnone — Python has no checked exceptionsevery Python exception
Checked.java
// will not compile — the compiler knows readAllLines can fail
static String load(String path) {
    return Files.readString(Path.of(path));
}
error: unreported exception IOException; must be caught or declared to be thrown
This is Day 15's rule, enforced by a compiler

Raise where the problem is detected; catch where you know what to do. Python asks you to remember that. Java writes it into the type system: throws IOException is a machine-checked statement that this method can fail in that way.

And the reason people argue about it

Checked exceptions produce try { ... } catch (Exception e) { } — empty catch blocks written purely to make the compiler stop complaining. That converts a loud failure into a silent one, which is worse than no checking at all. Kotlin, C# and Scala all looked at this feature and chose not to copy it. Whether it was a good idea is a genuinely open question — and you are now qualified to have a view.

2try-with-resources

Java's with statement, arrived at from the other direction.

Files.java
import java.nio.file.*;
import java.util.List;

Path path = Path.of("scores.txt");

// small files — read it all
String all = Files.readString(path);
List<String> lines = Files.readAllLines(path);

// writing
Files.writeString(path, "hello\n");
Files.write(path, lines);

java.nio.file is the modern API and it is much closer to Python's pathlib than the older File/FileReader classes you will see in tutorials. Path.of(...) is Path(...); Files.readString is roughly path.read_text().

3JUnit 5

The same discipline as pytest, with more annotations.

Why JUnit needs a lambda and pytest does not

Both frameworks need the code not yet run, so they can run it themselves and watch for the exception. Python's with block does this by controlling the block. Java has no equivalent, so it takes a lambda instead. Different mechanism, identical purpose.

The assertions worth knowing

JUnitCheckspytest
assertEquals(a, b)Equal — expected firstassert a == b
assertEquals(a, b, delta)Equal within a toleranceassert a == pytest.approx(b)
assertTrue(x)Trueassert x
assertThrows(E.class, fn)Throws that typewith pytest.raises(E):
assertNull(x)Is nullassert x is None
Expected first, actual second

assertEquals(11.75, actual) — get the order wrong and the tests still pass, but every failure message is backwards, telling you it expected your buggy value and got the right one. pytest sidesteps this by using plain assert.

4Test-driven development

Write the failing test first. There is a real reason for the order.

The argument for writing the test first

It is not about discipline. Writing the test first forces you to use your function before you build it — so you design the signature from the caller's point of view. Awkward APIs are almost always written by someone who wrote the implementation first. This is Day 6's "write the docstring before the body", one step further.

And the honest caveat

Strict TDD for every line is a stricter discipline than most working teams actually keep. What genuinely matters: tests exist, they run automatically, and they were written close in time to the code. Test-first is a good habit and a bad religion.

Today's work: finish Mini-Project 4's JUnit suite. Aim for fifteen tests covering every subclass, every custom exception, and the file round-trip.

>_Python playground

A real Python interpreter running inside your browser. Nothing is installed, nothing is uploaded, nothing can break.

scratch.pypython not loaded
Values for input(), comma separated →
Output appears here. The first run takes a few seconds while Python loads.

Exercise set

Checked automatically the moment you submit. Work top to bottom — each one assumes the last. Your answers are saved in this browser.

All Warm-up Core Challenge Reset day

Day 22 — Clean Code, Refactoring & Code Review

Readability as a feature — smells, moves, and the review workflow.

Continue →