OE-3.3 Exceptions, Multithreading & Generics
Standard Java exceptions, threading and generics — written September 2026
What this is and why it exists
Three separate subjects share this unit, and one of them will cost you real money one day.
Checked exceptions are a Java-specific design decision that shapes how its libraries feel. Understand the flow precisely, and especially what finally guarantees.
Thread synchronisation is the part that bites in production. A race condition passes your tests and fails under load. So learn *why* synchronisation exists before learning its syntax. The syntax is quick and the reasoning is not.
The vocabulary
- Checked exception — one the compiler requires you to handle or declare.
- Unchecked exception — one it does not.
- `finally` — a block that runs whether or not an exception happened.
- Thread — an independent path of execution inside one program.
- Race condition — a defect whose appearance depends on timing.
- Synchronisation — restricting access so only one thread acts at a time.
- Generic — a class or method parameterised by a type.
- Bounded type — a type parameter restricted to a family of types.
The mental model
Java divides exceptions into ones the compiler insists you deal with and ones it does not. That decision shapes the whole library ecosystem — it is why so much Java code is wrapped in handling blocks, for better and for worse. Learn the flow exactly: the protected block, the handler for each type, and finally, which runs whether or not anything went wrong. `finally` is where you release things, because it is the only part guaranteed to execute.
Writing your own exception types is worth doing once. An exception carrying the specific thing that went wrong is far more useful to whoever debugs it than a general one carrying a message.
Then threads, and here the order of learning matters. Do not begin with the keyword. Begin with the problem. Two threads reading, modifying and writing the same value can interleave so that one update is lost entirely. Nothing crashes. The number is wrong, sometimes, depending on timing that varies with machine load. That is a race condition, and it is why tests do not catch it. The test ran once, on an idle machine, and won the race.
Once that problem is real to you, synchronisation is obvious: restrict the shared thing so only one thread touches it at a time. The syntax then takes ten minutes.
Generics are the third subject and the calmest. A generic class is parameterised by a type, so one implementation serves many types with the compiler checking each use. Before generics, collections held a general type and every retrieval needed a cast that could fail at run time. Generics move that failure to compile time, which is always the cheaper place for a failure to happen. Bounded types narrow the parameter to a family, so the code inside can rely on what that family provides.
What you should now be able to explain or do
Handle exceptions with the full flow, and say precisely what finally guarantees. Define your own exception type and say why a specific one beats a general one. Describe a race condition without using the word synchronisation. Explain why tests do not catch one. Apply synchronisation and say what it restricts. Write a generic class and method, and say which failures generics move to compile time.
Check yourself
What does finally guarantee?
That it runs whether or not an exception occurred, which is why releasing resources belongs there rather than after the protected block.
Why learn the problem before the synchronisation keyword?
Because the syntax takes ten minutes and the reasoning does not. Without the problem, the keyword is applied by superstition.
What is a race condition, and why do tests miss it?
A defect whose appearance depends on thread timing. A test runs once on an idle machine and usually wins the race, so nothing fails.
What do generics buy?
Compile-time checking of the types a container holds. Before them, retrieval needed a cast that could fail at run time instead.
What is a bounded type parameter for?
Restricting the parameter to a family of types, so the code inside can rely on what that family provides.
Go deeper
We haven't checked most of these for screen reader use yet.
Back to Exceptions, Multithreading & Generics: work through the checklist