Java gives you two kinds of value, one calling convention, and a runtime that manages memory but not your invariants. Almost every bug that survives review comes from misreading one of those three: treating a reference as if it were the object, trusting a check the compiler erased before the code ran, or assuming a field one thread wrote is a field another can see. This is the shape rather than a syntax tour — what the compiler guarantees, what it deliberately does not, and which ordinary-looking operations do something other than what they read like.
Each chapter opens with the short version. Tap one to read the detail.
Values: two kinds, and the arithmetic on one of them
~2 min
Java has exactly two kinds of value: eight primitives, and references to objects. Every argument is copied on the way in — the reference included — so a method can change what an object contains, never which object the caller's variable names.
Construction and dispatch: what is chosen when
~2 min
Instance methods are chosen by the object's runtime type; fields, static methods and which overload you called are chosen by the compile-time type. That asymmetry is why an overridable method called from a constructor can reach an unassigned subclass field.
The equals and hashCode contract
~2 min
These are one contract, not two methods. Override equals alone and your object goes into a hash-based collection and cannot be found again — and mutating a key after inserting it does the same thing to a perfectly correct implementation.
Modelling data: records, enums, sealed types, and the modern switch
~2 min
A record is a transparent carrier for its components — the compiler writes the constructor, accessors, equals, hashCode and toString. Its immutability is shallow: hand it a mutable list and callers can still change what is inside.
Collections: choosing by the operation you repeat
~2 min
Pick by the operation you do most: ArrayList for indexed reads, HashMap for lookup by key, LinkedHashMap when order must be insertion order, TreeMap when it must be sorted. Fail-fast iteration is a best-effort bug detector, never a guarantee.
Generics and erasure
~2 min
Type arguments are checked at compile time and erased before the code runs, so at runtime there is no List<String> — only List. Everything odd about generics follows: no generic arrays, no instanceof List<String>, and raw types that switch checking off.
Failure: checked, unchecked, and the two habits that hurt
~2 min
Checked exceptions are the ones the compiler makes you catch or declare; RuntimeException, Error and their subclasses are exempt. The damage in practice comes from catching something and doing nothing with it, and from letting finally complete abruptly.
Lambdas, streams, and Optional
~2 min
A lambda is an instance of a functional interface — one abstract method — and captures only effectively final locals. Stream pipelines are lazy and single-use: nothing runs until a terminal operation, and an operation the implementation proves unnecessary may never run.
Concurrency: visibility first, then mutual exclusion
~2 min
The hard part is not interleaving, it is visibility: with no happens-before edge between two threads, a write by one may never be seen by the other — not late, never. volatile and synchronized create those edges; i++ creates none.
The runtime: how code is found, loaded, and freed
~2 min
Each thread gets its own stack; every object lives on one shared heap reclaimed by reachability. Classes load lazily and initialise on first real use — which is why a failing static initialiser reports one error the first time and a different, more confusing one afterwards.
Text, files and clocks: where machine defaults leak in
~2 min
Strings are immutable and literals are pooled, so == sometimes works — which is what makes it a bug. Beyond that, everything reading a machine default (the charset, the locale, the clock and zone) behaves one way on your laptop and another in production.
Written by Keentune. We are not affiliated with or endorsed by the organizations whose documentation informs this guide, and any linked sources belong to their respective owners.
All exam, test, and product names and trademarks are the property of their respective owners and are used here for identification and reference only. Keentune is independent study practice — not affiliated with, authorized, or endorsed by any of these organizations.