Course contents

The final 48 hours: rapid-fire revision

A 48-hour, 24-hour and 1-hour plan before a Java interview, 60 tickable rapid-fire questions with crisp Java 21 answers, eight classic what-does-it-print puzzles, the project questions you will get, and how to recover when you blank.

FreeMust know for interviewsLesson28 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: the last 48 hours
  2. Rapid-fire: core Java, OOP and strings
  3. Rapid-fire: equals, hashCode and exceptions
  4. Rapid-fire: collections and HashMap
  5. Rapid-fire: concurrency and the Java memory model
  6. Rapid-fire: JVM memory and GC
  7. Rapid-fire: Java 8 to 21 and patterns
  8. What does it print? Eight classic puzzles
  9. The questions you'll be asked about your project
  10. How to recover when you blank
  11. The day-of checklist
  12. How to say it in the interview

⏱️ What is this sheet?

It's the last thing you read before a Java interview: a plan for the final 48 hours, a rapid-fire round of 60 questions with the exact answers interviewers expect, eight "what does it print?" puzzles, and a script for the moments you blank. Think of it as a pre-flight checklist: a pilot doesn't relearn how to fly before take-off, they run through the items that cause crashes when missed. Every answer here is correct for Java 21.

For this sheet, we'll switch from learning to recall. In the last two days, re-reading notes feels productive but barely moves your score; answering out loud without looking does. So each item below is a question you answer first, then check, then tick. If you can't answer one cleanly, the link at the top of its section takes you to the Last-Mile sheet that covers it.

Below the line (out of scope)

  • New topics. If you haven't met virtual threads or G1 tuning yet, 48 hours out isn't the time; skim the 30-second answer in the matching sheet and move on.
  • Full explanations: each section links to its sheet, starting with The can't-skip Java interview checklist.
  • The 15 and 30-day plans that lead up to this: How to use Last-Mile Java.

The 30-second answer

Forty-eight hours out, find your gaps: take the can't-skip checklist cold, fix only what you missed, rehearse your project story out loud and do one timed design problem. Twenty-four hours out, run this rapid-fire round and the eight puzzles, stop learning new material, sort out logistics, and sleep. In the last hour, read only your own one-page summary, warm up by saying two answers out loud and writing one small piece of code by hand, then go in. In the room, answer in three beats (the fact, the why, one example or number), think out loud when you're stuck, and never bluff: "I'm not sure, here's how I'd reason about it" scores better than a confident wrong answer.

What you’ll learn

  • Follow a concrete 48h, 24h and 1h plan that turns revision into recall instead of re-reading
  • Answer 60 rapid-fire questions across core Java, strings, exceptions, collections, concurrency, the JVM, Java 8 to 21 and patterns in one to three sentences
  • Predict the output of the eight classic puzzles: Integer cache, String ==, finally return, init order, null overloading, mutable keys, for-each remove and volatile count++
  • Prepare a two-minute project story and the follow-ups interviewers ask about your own system
  • Use a recovery script when you blank, and run the day-of checklist

Interview radar

Asked very often: The quick-fire opener: == vs equals, HashMap internals, checked vs unchecked, volatile, final vs finally vs finalize, what's new in Java 21. Senior rounds probe: The follow-up after each quick answer ("why?", "what breaks?", "what would you see in production?"), plus deep questions on your own project. Production angle: Most "what does it print?" puzzles are real bugs in disguise: a cached Integer compared with ==, a mutated HashSet key, a lost update on a volatile counter.

01Picture it first: the last 48 hours

The shape of the last two days matters more than the hours you put in. Each phase has a different job: the first finds gaps, the second makes recall fast, and the last hour only warms you up. The timeline below shows what goes in each block and, as importantly, what doesn't.

Fig. 1

A timeline from 48 hours to the interview: at 48 hours, find gaps with the checklist, rehearse the project story and do one timed design problem; at 24 hours, run the rapid-fire round and puzzles, stop new topics, fix logistics and sleep 7 to 8 hours; at 1 hour, read your one-page summary, warm up out loud and write one snippet by hand; then the interview

A timeline from 48 hours to the interview: at 48 hours, find gaps with the checklist, rehearse the project story and do one timed design problem; at 24 hours, run the rapid-fire round and puzzles, stop new topics, fix logistics and sleep 7 to 8 hours; at 1 hour, read your one-page summary, warm up out loud and write one snippet by hand; then the interview

48 hours out: find the gaps

  • Take the can't-skip checklist cold. No notes. Mark each item green (said it cleanly), amber (got there slowly) or red (couldn't). Spend the rest of the day on red only.
  • Rehearse out loud, not in your head. Pick the 10 questions you'd hate to get and answer each in under 90 seconds. Record yourself once; you'll hear the filler words and the missing "why".
  • Do one timed design problem. 45 minutes, parking lot or rate limiter, following the LLD Rulebook. Practise naming each pattern and the change it protects against (patterns sheet).
  • Write your project story (the section below) on one page, and say it out loud twice.

24 hours out: make recall fast

  • Run the rapid-fire round below. Tick only what you answered without peeking. Second pass on the unticked ones only.
  • Do the eight puzzles. Predict, then read. These are the questions where a confident wrong answer hurts most.
  • Stop new topics by the evening. A half-learned topic the night before tends to come out muddled and knock your confidence on the ones you did know.
  • Fix logistics: test the video link, camera, mic and a shared editor; for on-site, route and ID. Prepare two or three questions to ask them.
  • Sleep 7 to 8 hours. Memory consolidation happens during sleep; an all-nighter trades tomorrow's recall for tonight's reading.

1 hour out: warm up, don't cram

  • Read only your own one-page summary, or the BOARD boxes from the Last-Mile sheets. Nothing new.
  • Say two answers out loud: the HashMap put path and your project story's first 30 seconds. Your voice needs a warm-up as much as your memory does.
  • Write one snippet by hand: a thread-safe singleton or a ConcurrentHashMap.merge counter. It wakes up the "typing code while talking" skill.
  • Join 5 to 10 minutes early, water nearby, notifications off.

02Rapid-fire: core Java, OOP and strings

Answer each out loud first, then check. One to three sentences is the target length in a quick-fire round; the interviewer will ask for more if they want it. Full coverage: Core Java and OOP: the must-knows and String immutability.

  • Q: Is Java pass-by-value or pass-by-reference? A: Always pass-by-value. For an object, the value copied is the reference, so the method can mutate the object but reassigning the parameter never affects the caller's variable.
  • Q: JDK vs JRE vs JVM? A: The JVM runs bytecode; the JRE is the JVM plus the class libraries; the JDK adds tools like javac, jar, jlink and jcmd. Since Java 11, Oracle no longer ships a separate JRE; you use jlink to build a trimmed runtime.
  • Q: Overloading vs overriding? A: Overloading picks a method at compile time from the static argument types; overriding picks at run time from the receiver's actual class. Static and private methods aren't overridden; a static method with the same signature in a subclass hides the parent's.
  • Q: Abstract class vs interface in Java 21? A: An interface can have default, static and private (Java 9+) methods but no instance fields; a class can implement many interfaces. An abstract class can hold state and constructors, but you can extend only one.
  • Q: What does final mean on a class, a method and a variable? A: No subclasses, no overriding, and assign-once respectively. A final reference can't be reassigned, but the object it points to can still be mutated.
  • Q: final, finally, finalize? A: A modifier, a block that runs after try/catch, and an Object method called before GC. finalize has been deprecated for removal since Java 18 (JEP 421); use try-with-resources or Cleaner.
  • Q: Static nested class vs inner class? A: An inner class holds a hidden reference to its enclosing instance, so it can keep that instance alive (a classic leak); a static nested class doesn't. Default to static nested.
  • Q: How do you make a class immutable? A: Make it final with private final fields, no setters, defensive copies of mutable inputs and outputs, and don't leak this from the constructor. A record covers most of this, but its components are only shallowly immutable.
  • Q: What does a record generate? A: A final class with private final fields, a canonical constructor, accessors, and equals, hashCode and toString based on all components (final since Java 16). It can't extend another class but can implement interfaces.
  • Q: Why is String immutable? A: So pooled literals can be shared safely, the hash code can be cached, it's thread-safe without locks, and values checked for security (file paths, class names) can't change after the check.
  • Q: Where is the string pool? A: On the heap since Java 7 (before that, PermGen). Literals and compile-time constants are interned automatically; intern() adds others.
  • Q: How many objects does new String("hi") create? A: Up to two: the "hi" literal in the pool (if it isn't there yet) and a new String object on the heap. The copy shares the literal's backing array rather than duplicating the characters.
  • Q: StringBuilder vs StringBuffer? A: Same API; StringBuffer synchronizes every method, StringBuilder doesn't. Use StringBuilder; a single builder is almost never shared across threads.
  • Q: What are compact strings? A: Since Java 9, a String stores Latin-1 text in a byte[] at 1 byte per char, falling back to UTF-16 (2 bytes per char) only when needed, which roughly halves memory for ASCII-heavy data.

03Rapid-fire: equals, hashCode and exceptions

Full coverage: Core Java and OOP: the must-knows, Exceptions: the must-knows and The equals() and hashCode() contracts.

  • Q: == vs equals()? A: == compares references for objects (values for primitives); equals compares logical value if the class overrides it. Object.equals is identity.
  • Q: State the hashCode contract. A: Equal objects must return equal hash codes, and the hash must stay stable while the fields used by equals don't change. Unequal objects may collide.
  • Q: What happens if you override equals but not hashCode? A: It compiles and runs, but HashMap.get and HashSet.contains usually miss, because equal keys land in different buckets. You can end up with two "equal" keys in one map.
  • Q: Comparable vs Comparator? A: Comparable.compareTo is the class's single natural order; a Comparator is an external, pluggable order. Keep compareTo consistent with equals, or TreeSet and HashSet disagree (new BigDecimal("1.0") and "1.00" are one element in a TreeSet, two in a HashSet).
  • Q: Checked vs unchecked exceptions? A: Checked exceptions extend Exception but not RuntimeException, and the compiler forces you to catch or declare them. Unchecked ones are RuntimeException and Error subclasses.
  • Q: Should you catch Error? A: Generally no: OutOfMemoryError and StackOverflowError mean the JVM is in trouble. Catch them only at a top-level boundary to log and exit cleanly.
  • Q: Does finally always run? A: It runs on normal completion, return, break and exceptions. It doesn't run if the JVM stops first: System.exit, Runtime.halt, a crash, a killed process, or a daemon thread still inside try when the JVM exits.
  • Q: What does try-with-resources guarantee? A: Every AutoCloseable is closed in reverse order of declaration, even on exception. If close() also throws, that exception is attached as suppressed to the primary one (getSuppressed()) instead of hiding it.
  • Q: Can an overriding method throw a broader checked exception? A: No. It may throw the same, narrower or no checked exceptions, and any unchecked ones, so callers of the parent type stay correct.

04Rapid-fire: collections and HashMap

Full coverage: Collections and HashMap: the must-knows.

  • Q: Walk through HashMap.put. A: Compute h = key.hashCode(), spread it with h ^ (h >>> 16), pick the bucket with (n - 1) & hash, then walk the bucket comparing stored hash, == and equals; replace the value on a match, otherwise append a node. If the size passes the threshold, resize.
  • Q: Default capacity, load factor and resize? A: 16 buckets, load factor 0.75, so the first resize happens when the 13th entry goes in (threshold 12). Resizing doubles the table, and each node either stays at index i or moves to i + oldCapacity.
  • Q: When does a bucket become a tree? A: When one bucket's chain grows past 8 nodes (TREEIFY_THRESHOLD = 8) and the table has at least 64 buckets; below 64, the map resizes instead. A resize turns it back into a list at 6 nodes or fewer. A bad bucket then costs O(log n) instead of O(n).
  • Q: Nulls in HashMap, Hashtable and ConcurrentHashMap? A: HashMap allows one null key and any number of null values. Hashtable and ConcurrentHashMap allow neither, because in a concurrent map get returning null would be ambiguous.
  • Q: How does ConcurrentHashMap work in Java 8+? A: No segments: it CASes a node into an empty bin and synchronized-locks only the bin's head node otherwise, while get takes no lock. Use merge, compute and putIfAbsent for atomic read-modify-write.
  • Q: Fail-fast vs weakly consistent iterators? A: ArrayList and HashMap iterators check modCount and throw ConcurrentModificationException on a structural change not made through the iterator. Concurrent collections' iterators never throw; they may or may not reflect changes made during iteration.
  • Q: ArrayList vs LinkedList? A: ArrayList gives O(1) random access, amortised O(1) append and grows by 1.5x; LinkedList is O(n) to index and cache-unfriendly. Default to ArrayList, and ArrayDeque for queues and stacks.
  • Q: How is HashSet implemented? A: It wraps a HashMap whose keys are the set's elements and whose values are one shared dummy object. So the same equals/hashCode rules apply.
  • Q: List.of vs Arrays.asList? A: List.of (Java 9+) is fully unmodifiable and rejects null elements with an NPE. Arrays.asList is fixed-size but allows set, and writes through to the backing array.
  • Q: How do you build an LRU cache with the JDK? A: Extend LinkedHashMap with accessOrder = true in the constructor and override removeEldestEntry to return size() > capacity. Wrap it or lock it for concurrent use.

05Rapid-fire: concurrency and the Java memory model

Full coverage: Multithreading and the JMM: the must-knows and wait, notify and synchronized.

  • Q: What does volatile guarantee? A: Visibility and ordering: a write to a volatile happens-before every later read of it, so the reader also sees everything written before that write. It does not make count++ atomic.
  • Q: Name four happens-before rules. A: Unlocking a monitor happens-before a later lock of it; a volatile write happens-before later reads; Thread.start() happens-before the started thread's actions; a thread's actions happen-before another thread returns from join() on it.
  • Q: synchronized vs ReentrantLock? A: Both are reentrant and give the same memory guarantees. ReentrantLock adds tryLock with a timeout, interruptible locking, optional fairness and multiple Conditions, at the price of an unlock() you must put in finally.
  • Q: Rules for wait() and notify()? A: Call them while holding the object's monitor, or you get IllegalMonitorStateException. wait releases the lock; always call it in a while loop that re-checks the condition, because of spurious wakeups and stolen signals.
  • Q: sleep vs wait? A: Thread.sleep pauses without releasing any locks; wait releases the monitor and waits for a notify, interrupt or timeout.
  • Q: How do you prevent deadlock? A: Deadlock needs mutual exclusion, hold-and-wait, no preemption and a circular wait. Break the circle with a global lock order, or use tryLock with a timeout and back off.
  • Q: How does ThreadPoolExecutor handle a new task? A: Below core size it starts a thread; then it queues; if the queue is full it grows to max size; beyond that it calls the rejection handler. Executors.newFixedThreadPool uses an unbounded queue, so a slow consumer can grow it until OutOfMemoryError.
  • Q: What are virtual threads? A: Final in Java 21 (JEP 444): threads scheduled by the JVM onto a small pool of carrier threads, cheap enough to create one per task. In Java 21, blocking inside synchronized pins the carrier (fixed in JDK 24 by JEP 491), and you should never pool them.
  • Q: thenApply vs thenCompose? A: thenApply maps the result with a plain function; thenCompose flat-maps a function that itself returns a CompletableFuture, avoiding a nested future. Async variants without an executor run on ForkJoinPool.commonPool().
  • Q: Why is ThreadLocal risky in a thread pool? A: Pool threads live for the app's lifetime, so values stay reachable and leak between requests. Always remove() in a finally.

06Rapid-fire: JVM memory and GC

Full coverage: JVM memory and garbage collection: the must-knows and Java memory management: heap, G1 and the signals that matter.

  • Q: Name the JVM memory areas. A: The heap (objects, shared), one stack per thread (frames with locals), Metaspace (class metadata, in native memory since Java 8 replaced PermGen), the code cache for JIT output, plus PC registers and native stacks.
  • Q: What's the default GC in Java 21? A: G1, on any machine with at least 2 CPUs and about 2 GB of memory; on smaller machines the JVM picks Serial. G1 aims for a 200 ms pause target by default.
  • Q: What is the generational hypothesis? A: Most objects die young, so the heap is split into a young generation (Eden plus survivor spaces) collected often and cheaply, and an old generation collected rarely. Objects that survive enough young collections get promoted.
  • Q: What are GC roots? A: References the collector starts from: local variables on thread stacks, static fields of loaded classes, JNI references and active monitors. Anything not reachable from a root is garbage, cycles included.
  • Q: When would you pick ZGC? A: When pause times matter more than throughput, for example latency-sensitive services with large heaps. Its pauses are typically under 1 ms regardless of heap size; Java 21 added generational ZGC (-XX:+UseZGC -XX:+ZGenerational).
  • Q: Name three kinds of OutOfMemoryError. A: "Java heap space" (heap full of live objects), "Metaspace" (too many classes, often a class loader leak), and "unable to create native thread" (OS thread limit). With the Parallel collector, "GC overhead limit exceeded" means over 98% of time went to GC while recovering under 2% of the heap.
  • Q: How does class loading delegate? A: A loader asks its parent first: application, then platform, then bootstrap. That stops your code from replacing java.lang.String.

07Rapid-fire: Java 8 to 21 and patterns

Full coverage: Java 8 to 21: the must-knows and Design patterns and SOLID: the must-knows.

  • Q: Are streams lazy? A: Yes: intermediate operations only build a pipeline, and nothing runs until a terminal operation. A stream can be consumed once; reusing it throws IllegalStateException.
  • Q: map vs flatMap? A: map turns each element into one element; flatMap turns each element into a stream and flattens them, for example a list of orders into a stream of all their items.
  • Q: orElse vs orElseGet? A: orElse(x) evaluates x every time, even when the Optional has a value; orElseGet(supplier) calls the supplier only when empty. Use Optional for return types, not fields or parameters.
  • Q: What makes an interface functional? A: Exactly one abstract method (default and static methods don't count). @FunctionalInterface makes the compiler enforce it.
  • Q: Name the Java 21 features you'd mention. A: Virtual threads (JEP 444), pattern matching for switch (JEP 441), record patterns (JEP 440) and sequenced collections (JEP 431), all final. Java 21 is an LTS release, after 17, 11 and 8.
  • Q: What do sealed classes buy you? A: A permits list fixes the subclasses (final since Java 17), so a switch over them can be exhaustive without a default, and the compiler flags a missing case when you add a subtype.
  • Q: Best thread-safe singleton? A: An enum with one constant: the JVM guarantees one instance and it's safe against reflection and serialization. For lazy creation, the holder idiom; double-checked locking needs a volatile field.
  • Q: Decorator vs proxy? A: Both keep the interface. A decorator adds behaviour and is stacked by the client (BufferedInputStream); a proxy controls access (lazy loading, caching, transactions) and usually hides that it's there.
  • Q: Strategy vs state? A: Same shape, different driver: the client picks a strategy, while a state object replaces itself as the context moves through its lifecycle.
  • Q: DIP vs dependency injection? A: DIP is the principle that high-level code depends on abstractions it owns; DI is the technique of passing dependencies in, usually via the constructor. Spring is a tool that automates DI.

08What does it print? Eight classic puzzles

These are the questions where you get one shot. Read each, say your prediction out loud, then read the answer. Every one of them is a production bug wearing a puzzle costume.

1. The Integer cache

Try it yourself first

Predict all four lines.

Integer a = 127, b = 127;
Integer c = 128, d = 128;
Long e = 127L;
System.out.println(a == b);        // ?
System.out.println(c == d);        // ?
System.out.println(c.equals(d));   // ?
System.out.println(e.equals(127)); // ?

true, false, true, false. Autoboxing calls Integer.valueOf, which returns cached objects for -128 to 127 (JLS 5.1.7), so a and b are the same object, while each 128 is a new one. The last line is the sneaky one: 127 boxes to an Integer, and Long.equals returns false for anything that isn't a Long. The upper cache bound can be raised with -XX:AutoBoxCacheMax, which is one more reason never to compare wrappers with ==.

2. String ==

Try it yourself first

Which comparisons print true?

String s1 = "java";
String s2 = "ja" + "va";
String s3 = new String("java");
String half = "ja";
String s4 = half + "va";
final String fixed = "ja";
String s5 = fixed + "va";

System.out.println(s1 == s2);          // ?
System.out.println(s1 == s3);          // ?
System.out.println(s1 == s4);          // ?
System.out.println(s1 == s5);          // ?
System.out.println(s1 == s4.intern()); // ?

true, false, false, true, true. "ja" + "va" and fixed + "va" are compile-time constant expressions (a final variable with a constant initializer counts), so the compiler folds them into the pooled "java". half + "va" is computed at run time and creates a new object. intern() returns the pooled copy.

3. return inside finally

Try it yourself first

What do a() and b() return?

static int a() {
    try { return 1; }
    finally { return 2; }
}

static int b() {
    int x = 1;
    try { return x; }
    finally { x = 2; }
}

a() returns 2: a return in finally overrides the try's return, and it would also silently swallow an exception thrown from try. b() returns 1: the return value is evaluated and saved before finally runs, so changing the local afterwards doesn't affect it. Never return from finally.

4. Initialisation order

Try it yourself first

What does new Child(); new Child(); print?

class Parent {
    static { System.out.print("1 "); }
    { System.out.print("2 "); }
    Parent() { System.out.print("3 "); }
}

class Child extends Parent {
    static { System.out.print("4 "); }
    { System.out.print("5 "); }
    Child() { System.out.print("6 "); }
}

1 4 2 3 5 6 2 3 5 6. Static initialisers run once, parent first, when the class is initialised. Each new then runs the parent's instance initialisers and constructor, then the child's instance initialisers and constructor (JLS 12.5). The trap is printing 1 4 twice.

5. Overloading with null

Try it yourself first

What does print(null) print? What if you add a third overload, print(Integer i)?

static void print(Object o) { System.out.println("Object"); }
static void print(String s) { System.out.println("String"); }

print(null);

String. null fits both, and the compiler picks the most specific method: String is a subtype of Object (JLS 15.12.2.5). Add print(Integer) and it doesn't compile: "reference to print is ambiguous", because neither String nor Integer is more specific than the other. Overload resolution happens at compile time, so this is never a runtime error.

6. A mutable key in a HashSet

Try it yourself first

Point has correct equals and hashCode over x and y. Predict the three lines.

class Point {
    int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }
    @Override public boolean equals(Object o) {
        return o instanceof Point p && p.x == x && p.y == y;
    }
    @Override public int hashCode() { return 31 * x + y; }
}

Set<Point> set = new HashSet<>();
Point p = new Point(1, 2);
set.add(p);
p.x = 5;

System.out.println(set.contains(p));               // ?
System.out.println(set.contains(new Point(1, 2))); // ?
System.out.println(set.size());                    // ?

false, false, 1. The entry sits in the bucket for hash (1, 2). Looking up p now searches the bucket for (5, 2) and misses; looking up a fresh (1, 2) finds the right bucket, but equals fails against the mutated object. The element is stranded: you can't find it and you can't remove it. Keys must be immutable, which is why records and String make good keys.

7. Removing inside a for-each

Try it yourself first

What happens? Then: what if the condition removes "bob" instead?

List<String> names = new ArrayList<>(List.of("ann", "bob", "cid"));
for (String n : names) {
    if (n.equals("ann")) names.remove(n);
}
System.out.println(names);

It throws ConcurrentModificationException. The for-each uses an iterator, names.remove bumps modCount, and the iterator's next next() call notices. The twist: removing "bob", the second-to-last element, doesn't throw. After the removal the size is 2 and the iterator's cursor is 2, so hasNext() returns false, the loop ends, and "cid" is never visited. Use names.removeIf(n -> n.equals("ann")) or Iterator.remove().

8. volatile count++

Try it yourself first

Two threads, 100,000 increments each. What prints?

static volatile int count = 0;

public static void main(String[] args) throws InterruptedException {
    Runnable inc = () -> { for (int i = 0; i < 100_000; i++) count++; };
    Thread t1 = new Thread(inc), t2 = new Thread(inc);
    t1.start(); t2.start();
    t1.join(); t2.join();
    System.out.println(count);
}

Some number up to 200,000, and on a multi-core machine usually less, different on each run. count++ is three steps (read, add, write), and volatile makes each step visible but doesn't make the three atomic, so two threads read the same value and one update is lost. Fix it with AtomicInteger.incrementAndGet(), LongAdder under heavy contention, or a lock.

09The questions you'll be asked about your project

In most Java rounds, 10 to 20 minutes go to your own work, and it's the part candidates prepare least. The interviewer is checking that you owned something, understood why it was built that way, and can talk about numbers and trade-offs. Prepare a two-minute story with this shape: context and scale, your role, the architecture in one sentence, the hardest problem and how you solved it, the measurable result, and what you'd change.

  • Walk me through a project you're proud of. Two minutes, the shape above. End on a number: latency, throughput, cost, incidents.
  • What was your exact role? Say "I", not "we", for what you did. Interviewers discount answers that never separate the two.
  • Why did you choose X over Y? Have one real trade-off ready for your database, your messaging choice and your framework. "It was already there" is honest; add what you'd pick today and why.
  • What was the hardest bug? A concrete production issue: symptom, how you found it (logs, heap dump, thread dump, flame graph), root cause, fix, and what you changed so it couldn't recur.
  • How does it handle failure? Timeouts, retries with backoff, idempotency, what happens when a dependency is down.
  • How would it handle 10x traffic? Where does it break first: database connections, a lock, a single-threaded consumer, GC pauses? Name the bottleneck before the fix.
  • Where did you use concurrency? Thread pools and their sizes, what's shared, how it's protected. Expect a follow-up on ConcurrentHashMap or CompletableFuture if you mention them.
  • What would you do differently? One real regret plus what you learned. "Nothing" reads as lack of reflection.
Tip

Anything you mention is fair game for a deep follow-up. If you say "we used Kafka", expect "how did you handle duplicate messages?" Only name technologies you can go two questions deep on, and prepare those two questions.

10How to recover when you blank

Blanking happens to strong candidates too, usually on something they know well. What interviewers score is what you do next. Silence for 20 seconds feels like a minute to both of you; a calm, out-loud recovery reads as composure.

  1. Buy a few seconds honestly. "Let me think about that for a moment." Then actually think, out loud if you can.
  2. Restate the question. "So you're asking what happens when two threads put the same key at once?" It often unlocks the answer, and it catches misunderstandings.
  3. Reason from what you're sure of. "I know HashMap isn't thread-safe and that put can trigger a resize, so the risk is..." First-principles reasoning is a strong signal even when you don't land the exact fact.
  4. Bound your answer. "I don't remember the exact threshold; I believe it's 8 nodes per bucket, and here's why a threshold exists at all." A hedged, mostly right answer beats a confident wrong one.
  5. Ask for a nudge, or park it. "Could you give me a hint on which part you mean?" or "Can I come back to this?" Interviewers want to see you work; most will help.
  6. Never bluff. An invented API or a made-up number costs more than "I don't know", because it makes the interviewer doubt everything else you said.
Where candidates slip

Many candidates, after one weak answer, rush the next three to "make up for it" and lose more points than the original miss cost. Each question is scored mostly on its own. Take a breath, reset, and treat the next one as a fresh start.

11The day-of checklist

Tick these on the morning of the interview. None of them is about Java, and every one of them has cost someone a round.

  • Setup tested: video link opens, camera and mic work, screen sharing is allowed, laptop charged and plugged in, a backup (phone hotspot) ready.
  • Coding environment ready: you know whether it's a shared editor, an IDE or a whiteboard, and you've typed a small class in it once. No autocomplete means you should know Map.Entry, Collectors.groupingBy and ExecutorService signatures cold.
  • Your one-pager open for the last hour, and closed when the interview starts.
  • Project story said out loud once today, ending on a number.
  • Two or three questions for them written down: how the team handles on-call, what a first project looks like, how design decisions get made.
  • Water, notifications off, door closed, and 5 to 10 minutes of buffer before the start.
  • One reminder to yourself: think out loud, answer in three beats, and say "I'm not sure" rather than bluff.

12How to say it in the interview

When I run a quick-fire round, I'm listening for answers that come in three beats: the fact, the reason, and one example or number. "volatile gives visibility, not atomicity" is the fact; "because count++ is a read, an add and a write" is the reason; "so I'd use an AtomicInteger or LongAdder" is the example. Candidates who stop at the fact sound memorised; candidates who start with the example sound unsure. Three beats, then stop and let me follow up.

In the interview

"Good question. Short version: HashMap isn't thread-safe, so two threads putting at once can lose an update, and before Java 8 a concurrent resize could even create a cycle that hung get. The reason is that put reads and writes the bucket array without any lock or happens-before edge. In production I'd use a ConcurrentHashMap, and if I'm doing read-modify-write like counting, I'd use merge or compute so the update is atomic per key. Want me to go into how ConcurrentHashMap locks per bin?"

Here's what your one-page summary for the last hour might look like:

On the whiteboard

Final 48 hours

  • 48h: checklist cold → fix red only · 10 answers out loud · 1 timed LLD · project story
  • 24h: rapid-fire + 8 puzzles · no new topics · logistics · sleep 7 to 8h
  • 1h: own summary only · say 2 answers · write 1 snippet · join early
  • Answer = fact → why → example/number, then stop
  • Puzzles: Integer cache -128..127 · constant folding · finally return wins · static once, parent first · null → most specific · mutable key stranded · CME (except 2nd-to-last) · volatile ≠ atomic
  • Blank: restate → reason from basics → bound it → ask/park → never bluff

Interview questions for this topicComing soon

Further reading (8)