Java, from your first program to mastery
Eleven stages in dependency order, with what to learn, what to build, and how to tell you actually finished each one. Roughly 400 hours of deliberate work end to end — most people take six to eighteen months, and skipping stages is what makes Java feel harder than it is.
- Stages
- 11
- Topics
- 94
- Hours of work
- ~401
- Deep dives
- 5
- beginner — 4 stages, ~101h
- intermediate — 3 stages, ~125h
- advanced — 3 stages, ~145h
- master — 1 stage, ~30h
How to use this
Do not read this like a checklist. Each stage ends with a milestone you have to build, and the milestone is the test — if you cannot produce it without copying, the stage is not finished no matter how many topics you have read. Where a topic links to a deep dive, read it when you hit that topic, not before.
- 1
Run your first program without an IDE
beginner~6hUnderstand what actually happens between a .java file and output on your screen. Doing this once by hand means IDE errors stop being magic.
You have finished this stage when
Compile and run a multi-class program from a terminal using javac and java, with no IDE open, and explain what the .class files are.
JDK vs JRE vs JVM
Which one you install, and why 'JRE' barely exists as a separate download any more.
Installing a JDK and picking a version
Choose an LTS — 21 or 25. Know why you would not start on 8.
javac and java on the command line
Compile to .class, run by class name, understand what -cp does.
The main method signature
Why it must be public static void main(String[]) and what each keyword is doing.
JShell for experiments
Test a line of Java in two seconds without a class or a build.
Choosing an IDE
IntelliJ IDEA Community or VS Code. Configure it after you can build without it.
- 2
Values, types and control flow
beginner~30hThe mechanical core of the language. The one idea that matters more than all the syntax: the difference between a primitive and a reference.
You have finished this stage when
A command-line program that reads numbers from the user, validates the input, and prints a formatted table of results — with no crash on bad input.
Primitives and their ranges
int, long, double, boolean, char. Why int overflows silently at ~2.1 billion.
References vs primitives
A variable holds a value or an address. This single distinction explains most beginner bugs.
Integer vs int, and autoboxing
Where boxing happens invisibly, and why == on Integer breaks above 127.
double is not for money
0.1 + 0.2 != 0.3. Use BigDecimal for currency, and know why.
var, and where it is allowed
Local variables only. It is inference, not dynamic typing.
Operators and precedence
Integer division truncating, % on negatives, ++ in expressions, short-circuit && and ||.
if, switch, and switch expressions
Old switch falls through; a switch expression with -> does not and can return a value.
Loops, break and continue
for, while, do-while, enhanced for. When an index loop is the wrong tool.
Arrays
Fixed length, zero-indexed, default-initialised. Arrays.toString and 2D arrays.
Strings for beginners
Immutable, compared with equals not ==, and formatted with printf or formatted().
- 3
Methods and how a program is organised
beginner~20hTurn one long main method into named pieces, then into files and packages. This is where code starts being readable by someone else.
You have finished this stage when
Refactor your stage-2 program into at least three classes in two packages, with no logic left in main beyond wiring.
Methods, parameters, return values
Java passes everything by value — including references, which is why the object can still be mutated.
Overloading
Same name, different parameters. How the compiler picks, and why widening beats boxing.
static vs instance
What belongs to the class and what belongs to an object. Why static is not free of consequences.
Scope and shadowing
Block, method, field. Why a parameter named the same as a field silently wins.
Packages and imports
Directory structure is the package name. What a wildcard import actually costs.
Access modifiers
public, protected, package-private, private. Default to the most restrictive that compiles.
Javadoc
Document the contract and the why, not the syntax.
- 4
Objects and OOP that holds up
beginner~45hThe stage most tutorials rush and most interviews probe. Aim for the reasoning behind each mechanism, not the four-bullet definition.
You have finished this stage when
Model a small domain — orders, payments, whatever — using interfaces for behaviour and records for data, with no inheritance used purely for reuse.
Classes, fields, constructors
Constructor chaining with this(), why a field should usually be final.
Encapsulation, and why getters are not the point
Hiding state means protecting invariants, not adding a getter per field.
Inheritance and super
extends, method overriding, @Override, and why a constructor cannot be overridden.
Polymorphism
One reference type, many runtime types. Dynamic dispatch is the mechanism.
Abstract classes vs interfaces
State and partial implementation vs contract and multiple inheritance of behaviour.
Composition over inheritance
Inheritance couples you to a superclass forever. Prefer delegating to a field.
Object's methods
Deep dive →toString, equals, hashCode, getClass. Everything you write inherits these.
Records
A semantic claim that a type IS its data — equals, hashCode and toString come free.
Enums
Type-safe constants that can hold fields and methods, and switch exhaustively.
Immutability in practice
final fields are not enough — you need defensive copies on the way in and out.
static nested vs inner classes
An inner class holds a hidden reference to its outer instance. That is a leak waiting to happen.
- 5
The core library you will use every day
intermediate~50hCollections and generics. This is the densest part of real Java work and the densest part of any interview.
You have finished this stage when
An in-memory repository that stores records, looks them up by key in O(1), returns them sorted several ways, and groups them — all without a database.
List, Set, Map — choosing between them
Pick by the question you need to answer, not by familiarity.
ArrayList vs LinkedList
Deep dive →Measure it. The folklore about mid-list insertion is wrong.
HashMap internals
Deep dive →Buckets, hashing, collisions, resize, treeify. The most-asked question in Java.
Generics and type parameters
Compile-time safety, and why List<Object> is not a supertype of List<String>.
Type erasure and wildcards
Generics vanish at runtime. PECS: extends to read, super to write.
Iteration and ConcurrentModificationException
Why removing during a for-each throws — and the case where it silently does not.
Comparable and Comparator
Natural order vs supplied order, and why an inconsistent compare() throws from inside the sort.
String, StringBuilder and concatenation
Deep dive →Immutability, the pool, and what + actually compiles to on a modern JDK.
Optional, used properly
A return type. Never a field, never a parameter.
java.time
LocalDate, Instant, ZonedDateTime, Duration. Never touch Date or Calendar again.
- 6
Failure, files and resources
intermediate~30hWhere the difference between a ten-minute incident and a two-day one is decided. Handling failure well is a senior skill you can start now.
You have finished this stage when
An importer that reads a CSV or JSON file, reports every bad row with its line number, and finishes the good rows instead of dying on the first problem.
Checked vs unchecked exceptions
Deep dive →The mechanism, and why modern frameworks abandoned checked exceptions.
try, catch, finally
How finally can silently discard the exception you needed to see.
try-with-resources and suppressed exceptions
It preserves the original failure. That is correctness, not convenience.
Designing a custom exception
Extend RuntimeException, always accept a cause, carry fields instead of a formatted string.
Reading NullPointerExceptions
Helpful NPE messages name the exact expression that was null — if you compiled with debug info.
java.nio.file
Path, Files.readString, Files.lines, and why you should not use File any more.
Streams of bytes and characters
InputStream vs Reader, and why an explicit charset is not optional.
Serialization, and why to avoid it
Java serialization is a security liability. Use JSON with a library instead.
- 7
Modern Java
intermediate~45hThe largest change in how Java is written. Everything from Java 8 onward that you are now expected to know by default.
You have finished this stage when
Rewrite your stage-5 repository using streams — then identify the places where the loop was clearer and put those back, with a reason.
Lambdas and functional interfaces
A lambda is an implementation of a single-method interface. No functional interface declares throws.
Method references
Four forms. The unbound instance form silently changes what the first parameter means.
Streams and laziness
Nothing runs until a terminal operation. peek() proves it in one line.
Collectors
groupingBy, partitioningBy, joining, toMap — and how toMap throws on duplicate keys.
When not to use a stream
Loops win for early exit, index arithmetic, and debuggability.
parallelStream and its traps
It uses one shared pool for the whole JVM. One slow task starves everything.
switch expressions and pattern matching
Return values, no fall-through, exhaustiveness, and instanceof with a binding.
Sealed types
A closed set of subtypes lets the compiler prove your switch is complete.
Text blocks
Multi-line strings, and how incidental indentation is stripped.
The module system, in practice
Mostly why reflection into java.* now needs --add-opens.
- 8
Concurrency
advanced~60hWhere senior rounds are decided. Every question here has a wrong answer that sounds right, and correctness cannot be checked by running it once.
You have finished this stage when
Fetch from several sources in parallel with a bounded pool, a timeout per task, and no shared mutable state — then explain why it is correct rather than saying it works.
Threads, and why you rarely create one
Thread, Runnable, join. Then never do this by hand again.
Races, atomicity and visibility
Three different problems. count++ is not atomic; volatile does not make it so.
synchronized and locks
What the monitor protects, why lock scope matters, and how deadlock happens.
The Java memory model
happens-before is the only correct mental model. 'It works on my machine' is not one.
Concurrent collections
ConcurrentHashMap over synchronizedMap, and why HashMap is still not thread-safe.
ExecutorService and pool sizing
An unbounded queue turns a pool into a memory leak with a rejection policy that never fires.
CompletableFuture
Composing async work, and how thenApply vs thenApplyAsync changes which thread runs your code.
Virtual threads
They fix blocking I/O, not CPU-bound work. Know what pinning was.
ThreadLocal and pooled threads
Pooled threads never die, so the value never becomes unreachable. That is the leak.
- 9
The JVM underneath
advanced~45hStop guessing about performance and memory. The goal here is a measurement habit, not a set of facts.
You have finished this stage when
Take a heap dump from a program that leaks, find the retaining path, fix it, and prove the fix with a second dump.
Class loading and initialisation
When static initialisers run, and what a ClassLoader leak looks like.
Heap, stack and Metaspace
What lives where, and why escape analysis makes the rule less absolute than tutorials say.
Garbage collection
Generational collection, G1 as the default, and why you should not tune before measuring.
Memory leaks in a managed language
Reachability, not allocation. Static collections, listeners, ThreadLocals, ClassLoaders.
Heap dumps and profiling
JFR, VisualVM, jcmd, jmap. Learn the tools before you need them at 2am.
JIT compilation
Interpretation, C1, C2, inlining, warm-up. Why your first benchmark result is a lie.
Benchmarking with JMH
Dead-code elimination and warm-up are why hand-rolled timing loops mislead.
Reading a stack trace properly
Caused by, suppressed, and where the real frame is.
- 10
Build, test and ship
advanced~40hEverything around the language that a job actually requires. A developer who cannot write a test is not employable at this level.
You have finished this stage when
A project on Maven or Gradle with a test suite that fails the build when broken, running in CI on every push.
Maven or Gradle
Dependencies, the build lifecycle, and what transitive dependency resolution does.
Dependency and version management
Version conflicts, BOMs, and auditing what you actually shipped.
JUnit 5
Lifecycle, assertions, parameterised tests, and testing that an exception is thrown.
Writing tests worth having
Test behaviour, not implementation. A test that mirrors the code proves nothing.
Mockito, and when not to mock
Mock the boundary you do not own. Mocking your own domain is a design smell.
Testcontainers
Test against a real database in Docker instead of an in-memory imitation.
Logging
SLF4J with an implementation, parameterised messages, levels that mean something, no PII.
Continuous integration
Build, test and static analysis on every push, failing loudly.
- 11
Judgement
master~30hWhat separates someone with eight years from someone with two years and six repetitions. None of this is syntax, and none of it is memorisable.
You have finished this stage when
Review a stranger's pull request and justify every comment with a mechanism or a measurement — no 'best practice' without a because.
API design
Make the wrong call hard to write. Names, defaults, and what you can never take back.
An error-handling strategy
One decision per layer about what it throws, what it wraps, and what it logs.
Reading the JDK source
It is on your machine. Reading HashMap.java is faster than reading ten articles about it.
Knowing what changed and when
Which LTS you are on, what the next one changes, and what breaks on migration.
Measuring instead of believing
Profile before optimising, benchmark properly, and be willing to be wrong.
Explaining a mechanism out loud
If you cannot explain why, you have memorised it. This is exactly what interviews test.
What to learn after Java
Spring Boot, JPA and SQL, HTTP and REST, Docker, and one other language on the JVM.
Preparing for an interview instead?
The roadmap teaches the language. If you already know Java and have a round booked, the questions are indexed by how many years of experience you are interviewing at.