AmouAI Hub/Courses/Programming Fundamentals/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.
By the end of today you can
- Tell a checked exception from an unchecked one, and say why the split exists
- Choose between handling an exception and declaring
throws - Use try-with-resources, and say what it guarantees
- Write a custom exception and decide which kind it should be
- Write and run a JUnit 5 test
- Assert that something throws, with
assertThrows - 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.
throws · why the feature is genuinely argued about · try-with-resources as Java's with · the modern java.nio.file API.@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.
| Checked | Unchecked | |
|---|---|---|
| Extends | Exception | RuntimeException |
| Compiler demands | You handle it or declare it | Nothing |
| Means | Something outside your control failed | A bug in the code |
| Examples | IOException, FileNotFoundException | NullPointerException, IllegalArgumentException |
| Python equivalent | none — Python has no checked exceptions | every Python exception |
// will not compile — the compiler knows readAllLines can fail
static String load(String path) {
return Files.readString(Path.of(path));
}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.
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.
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.
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
| JUnit | Checks | pytest |
|---|---|---|
assertEquals(a, b) | Equal — expected first | assert a == b |
assertEquals(a, b, delta) | Equal within a tolerance | assert a == pytest.approx(b) |
assertTrue(x) | True | assert x |
assertThrows(E.class, fn) | Throws that type | with pytest.raises(E): |
assertNull(x) | Is null | assert x is None |
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.
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.
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.
input(), comma separated →
✓Exercise set
Checked automatically the moment you submit. Work top to bottom — each one assumes the last. Your answers are saved in this browser.
Day 22 — Clean Code, Refactoring & Code Review
Readability as a feature — smells, moves, and the review workflow.