Modern Java interview questions 40 questions in 6 chapters
- 01Java 8 core features7 questions
- 02Java 9 to 115 questions
- 03Java 12 to 177 questions
- 04Java 18 to 218 questions
- 05Advanced Java and JVM8 questions
- 06Production scenarios5 questions
Java 8 core features
Lambdas, streams, CompletableFuture, Optional and interface default methods.
1.1 What are functional interfaces and lambdas? Easy 2 min
A functional interface is an interface with exactly one abstract method, like Runnable, Function or Predicate. A lambda is just a short way to write an implementation of that one method, so I can pass behavior around like data. The FunctionalInterface annotation is optional; it only asks the compiler to fail if someone adds a second abstract method.
Read the full answer1.2 What is the difference between map() and flatMap()? Easy 1 min
Map turns each element into exactly one new element, so a stream of users becomes a stream of names. FlatMap turns each element into a whole stream and then joins all those small streams into one. I use it when each item has many children, like orders with line items, and I want one flat stream instead of a stream of lists.
Read the full answer1.3 How does the Stream API work internally? Medium 1 min
A stream is a pipeline: a source, some intermediate steps like filter and map, and one terminal step like collect. The intermediate steps only describe the work. When the terminal step runs, each element flows through all the steps one at a time, not stage by stage. A stream can be used once, and parallel streams split the source and run on the common fork-join pool.
Read the full answer1.4 What is lazy evaluation in streams? Medium 1 min
Intermediate operations like filter and map do nothing on their own. Work only starts when a terminal operation runs, and then the stream does only as much as it needs. That is why short-circuit operations like findFirst, anyMatch or limit can stop early, even on an infinite stream. It also means a pipeline with no terminal operation never executes, so side effects inside it never happen.
Read the full answer1.5 What is the difference between Future and CompletableFuture? Medium 1 min
A Future only lets you check if the work is done, cancel it, or block on get to wait for the result. CompletableFuture, added in Java 8, lets me chain the next steps without blocking: transform the result, call another async step, combine two results, or wait for many. It also handles errors in the chain. For blocking I/O, I pass my own executor instead of using the common pool.
Read the full answer1.6 How does Optional help avoid null checks? Easy 1 min
Optional puts "there might be no value" into the method's return type, so the caller can't forget to handle it. Instead of if-not-null checks, I chain map, filter and then orElse, orElseGet or orElseThrow. The Javadoc says it is mainly meant for return values, so I don't use it for fields or parameters, and an Optional variable itself should never be null.
Read the full answer1.7 What is the difference between default and static methods in interfaces? Easy 1 min
A default method has a body inside the interface and is inherited, so implementing classes get it for free but can override it. It was added so the JDK could add methods like forEach to existing interfaces without breaking every implementation. A static interface method belongs only to the interface; you call it through the interface name, and implementing classes don't inherit it.
Read the full answer
Java 9 to 11
Modules, collection factories, private interface methods, var and new String methods.
2.1 What is JPMS, the Java module system? Medium 1 min
Java 9 added modules. A module descriptor says what the module is called, which modules it needs, and which packages it exports. That gives two things: missing dependencies fail at startup instead of at runtime, and packages that are not exported are truly hidden, even from reflection by default. The JDK itself was split into modules, which also lets you build a small custom runtime with jlink.
Read the full answer2.2 What is the difference between List.of() and Arrays.asList()? Easy 1 min
List.of, from Java 9, gives a truly unmodifiable list: add, set and remove all throw, and it rejects null elements. Arrays.asList gives a fixed-size view over an array: I can't add or remove, but I can set an element, and that change writes through to the original array. Arrays.asList also allows nulls. So List.of is safer for constants and return values.
Read the full answer2.3 Why were private interface methods added? Easy 1 min
Once interfaces had default methods, several of them often needed the same helper code. Before Java 9, the only option was another default or static method, which made that helper part of the public API. Since Java 9, an interface can have private methods, both instance and static, so default methods can share logic without exposing it to implementing classes or callers.
Read the full answer2.4 What is var and where can you use it? Easy 1 min
Var, added in Java 10, lets the compiler infer a local variable's type from what's on the right side. It is still fully static typing; the type is fixed at compile time. It only works for local variables with an initializer, loop variables, and, since Java 11, lambda parameters. It can't be used for fields, method parameters or return types, and var x = null won't compile.
Read the full answer2.5 Which new String methods came in Java 11? Easy 1 min
Java 11 added isBlank, which is true for empty or whitespace-only strings; lines, which gives a stream of lines; strip, stripLeading and stripTrailing, which remove Unicode whitespace; and repeat, which repeats a string n times. The key difference is strip versus the old trim: trim only removes characters up to the plain space code, while strip understands all Unicode whitespace.
Read the full answer
Java 12 to 17
Switch expressions, text blocks, records, sealed classes, pattern matching for instanceof and Java 17 platform changes.
3.1 What are switch expressions? Easy 1 min
Since Java 14, switch can be an expression that returns a value. The arrow form has no fall-through, so no forgotten break. One case can list several labels, and for a block you return the value with yield. Because it must always produce a value, the compiler checks it is exhaustive, so for an enum you either cover every constant or add a default.
Read the full answer3.2 What are text blocks? Easy 1 min
Text blocks, final in Java 15, are multi-line string literals between three double quotes. You write JSON, SQL or HTML as it looks, without escaping every quote or joining lines with plus signs. The compiler removes the common indentation, so you can indent the block with your code. The result is a normal String, so you can call formatted on it to fill in values.
Read the full answer3.3 What are records and when should you use them? Easy 1 min
A record, final in Java 16, is a short way to declare a class that just carries data. From one line, the compiler generates private final fields, a constructor, accessor methods, and equals, hashCode and toString based on all the fields. I use them for DTOs, value objects, map keys and returning several values. Validation goes in a compact constructor.
Read the full answer3.4 What are sealed classes? Medium 2 min
Sealed classes, final in Java 17, let a class or interface decide exactly which types may extend it, using a permits list. Each allowed subtype must say whether it is final, sealed again, or non-sealed. This models a closed set of cases, like payment types. The big win is that the compiler can check a switch over a sealed type covers every case, without a default.
Read the full answer3.5 What is pattern matching for instanceof? Easy 1 min
Since Java 16, instanceof can test the type and bind a variable in one step, so I don't need a separate cast afterwards. For example, if obj is a String s, I can use s directly. The variable only exists where the compiler knows the match succeeded, so it also works after an and condition, or after an early return when the check fails.
Read the full answer3.6 How is a record different from a traditional class? Medium 1 min
A record's fields are always final and set through its constructor, and equals and hashCode always use all the components. A record can't extend another class, because it already extends Record, and it can't add extra instance fields. It can implement interfaces and have methods. Also, it is only shallowly immutable: a list inside can still change unless I copy it in the constructor.
Read the full answer3.7 What JVM and platform improvements do you get by moving to Java 17? Medium 2 min
Java 17 is a long-term support release, so coming from 8 or 11 you collect a lot. ZGC and Shenandoah became production-ready low-pause collectors in Java 15. NullPointerExceptions now say exactly which variable was null. JDK internals are strongly encapsulated, which is the usual upgrade blocker for old reflection-heavy libraries. You also get records, sealed classes, switch expressions and text blocks.
Read the full answer
Java 18 to 21
Virtual threads, structured concurrency, scoped values, pattern matching for switch, sequenced collections and generational ZGC.
4.1 What are virtual threads? Medium 1 min
Virtual threads, final in Java 21, are lightweight threads managed by the JDK instead of the operating system. They are still normal Thread objects, so ordinary blocking code works. When a virtual thread waits on I/O, the JDK unmounts it from the real OS thread underneath, and that OS thread runs another virtual thread. So I can have one thread per request, even with a huge number of requests.
Read the full answer4.2 How do virtual threads differ from platform threads? Medium 1 min
A platform thread is a thin wrapper over one OS thread for its whole life. It's expensive, so we pool them. A virtual thread is cheap: you make one per task and never pool it. They don't make code faster; they let many more tasks wait at once, so they help throughput for I/O-heavy work, not CPU-heavy work. In Java 21, watch out for pinning inside synchronized blocks.
Read the full answer4.3 How do virtual threads improve scalability? Hard 1 min
For a server, the number of requests in progress equals throughput times latency; that's Little's Law, and JEP 444 uses it. With one blocking platform thread per request, the OS thread count caps how many requests can be in progress, so it caps throughput. Virtual threads remove that cap. I keep simple blocking code but can handle far more waiting requests, without rewriting everything in reactive style.
Read the full answer4.4 What is structured concurrency? Hard 1 min
Structured concurrency treats a group of subtasks as one unit of work. I open a scope, fork subtasks like fetching a user and their orders, then join. If one fails, the others are cancelled, and no subtask can outlive the scope, so no thread leaks. In Java 21 it is only a preview API, so it needs the enable-preview flag and isn't final yet.
Read the full answer4.5 What are scoped values? Hard 1 min
A scoped value shares read-only data, like the current user or request id, with every method called inside a bounded block, without passing it as a parameter. It's a safer ThreadLocal: callees can't change it, it disappears automatically when the block ends, and child tasks inherit it cheaply. It was a preview in Java 21 and became final later, in Java 25.
Read the full answer4.6 What is pattern matching for switch? Medium 1 min
Final in Java 21, switch cases can match on types instead of only constants, with guards using when, and a case for null. Combined with record patterns, also final in 21, a case can take a record apart into its components directly. Over a sealed type, the compiler checks every subtype is covered, so I get type-safe branching without instanceof chains or the visitor pattern.
Read the full answer4.7 What are sequenced collections? Easy 1 min
Java 21 added interfaces for collections with a defined order: sequenced collection, sequenced set and sequenced map. They give one common way to get the first and last element, add or remove at either end, and get a reversed view. Before this, getting the last element meant different code for a list, a deque or a linked hash set. Now it's just getLast.
Read the full answer4.8 What is Generational ZGC? Hard 1 min
ZGC is the low-pause collector that does nearly all its work while the application keeps running. Java 21 added a generational mode that keeps young and old objects apart, so it can collect short-lived objects often and cheaply. In Java 21 you have to turn it on with an extra flag next to the normal ZGC flag. Later releases made generational the default and then the only mode.
Read the full answer
Advanced Java and JVM
Locks, atomics, ConcurrentHashMap, executors, concurrency bugs, garbage collection and JVM memory areas.
5.1 What is the difference between synchronized and ReentrantLock? Medium 1 min
Both give mutual exclusion and the same memory visibility guarantees. Synchronized is simpler and always releases the lock when the block ends, even on an exception. ReentrantLock gives more control: try to lock with a timeout, wait in a way that can be interrupted, optional fairness, and multiple conditions. The cost is that I must unlock in a finally block myself.
Read the full answer5.2 What is the difference between volatile and AtomicInteger? Medium 2 min
Volatile only guarantees visibility and ordering: every thread sees the latest write to that variable. But count plus plus is a read, an add and a write, so two threads can still lose updates with volatile. AtomicInteger makes the whole increment atomic using compare-and-set, without a lock. So I use volatile for a simple stop flag and atomics for counters; under heavy contention, LongAdder.
Read the full answer5.3 How does ConcurrentHashMap work internally? Hard 2 min
ConcurrentHashMap lets many threads read and write without locking the whole map. Reads usually don't block, and writes only lock a small part of the table, so writers on different keys rarely wait for each other. Methods like compute, computeIfAbsent and merge are atomic per key. Size is only an estimate during updates, iterators never throw concurrent modification errors, and null keys or values aren't allowed.
Read the full answer5.4 What is the difference between ExecutorService and ForkJoinPool? Medium 2 min
ExecutorService is the general interface for running tasks on a pool; the classic version, ThreadPoolExecutor, has workers that take tasks from one shared queue. ForkJoinPool is one implementation built for work stealing: each worker has its own queue, and idle workers steal tasks from busy ones. It fits divide-and-conquer and many small tasks. Parallel streams and default CompletableFuture async calls use its common pool.
Read the full answer5.5 What are deadlock, starvation, livelock and race conditions? Medium 2 min
A deadlock is when two threads each hold a lock the other needs, so both wait forever. Starvation is when one thread rarely gets a resource because others keep taking it. Livelock is when threads keep reacting to each other but make no progress. A race condition is when the result depends on timing, like two threads incrementing the same counter. Fixes: consistent lock order, timeouts, and atomic or concurrent classes.
Read the full answer5.6 How does garbage collection work in the JVM? Medium 1 min
The garbage collector finds objects that can no longer be reached from roots, like thread stacks and static fields, and frees their memory. Most HotSpot collectors are generational, because most objects die young: the young area is collected often and cheaply, and objects that survive long enough move to the old area. Collectors trade throughput, pause time and memory. G1 is the default on most server machines.
Read the full answer5.7 How do G1 and ZGC compare? Hard 1 min
G1, the default, splits the heap into regions and tries to meet a pause-time goal, two hundred milliseconds by default, while keeping good throughput. ZGC does almost all its work while the application runs, so pauses stay very short even on huge heaps, at the cost of some CPU and memory overhead. I'd keep G1 for general services and pick ZGC when tail latency really matters.
Read the full answer5.8 What are the JVM memory areas? Medium 1 min
Each thread has its own program counter, its own JVM stack with a frame per method call holding local variables, and a native method stack. All threads share the heap, where every object and array lives and which the garbage collector manages, and the method area, which holds class data and code. In HotSpot since Java 8, class metadata lives in native memory called Metaspace, not in the heap.
Read the full answer
Production scenarios
High CPU, GC pauses, memory optimization, high concurrency and migrating from Java 8 to 21.
6.1 How do you troubleshoot high CPU in a Java service? Hard 2 min
First I confirm it's the Java process and check whether garbage collection is burning the CPU, using the GC logs. If not, I find the hot threads: take a few thread dumps a few seconds apart and see which stacks stay busy. Then I record a short Flight Recorder profile to find the hot methods. Typical causes are busy loops, retry storms, heavy regex or serialization, and excessive logging.
Read the full answer6.2 How do you investigate frequent GC pauses? Hard 2 min
I turn on GC logging and look at how often pauses happen, how long they are, whether they're young or full collections, and how much heap is still used after each one. Frequent young pauses usually mean a high allocation rate. Old-generation usage that keeps climbing after every collection suggests a leak. Full collections in G1 usually mean the heap is too small. Then I reduce allocation, resize, or consider ZGC.
Read the full answer6.3 How do you optimize memory usage in a Java application? Medium 1 min
I measure before changing anything: heap used after garbage collection, plus a heap dump and a class histogram to see what's really taking space. Then I fix leaks like unbounded caches, static maps, listeners that are never removed, and thread locals never cleared. I stream large data instead of loading it all, use leaner data structures, and size the heap from measured live data, including container limits.
Read the full answer6.4 How would you handle thousands of concurrent API requests? Hard 2 min
For mostly I/O-bound requests on Java 21, I'd use virtual threads, one per request, so threads stop being the bottleneck. Then I protect the real limits: bounded database connections, timeouts on every remote call, and a cap on concurrent calls to each downstream service. When overloaded, I reject or queue extra requests instead of falling over. Caching, batching and scaling out behind a load balancer cover the rest.
Read the full answer6.5 How would you migrate an application from Java 8 to Java 21? Hard 2 min
I'd upgrade build tools and libraries first, because old bytecode tools and frameworks are the usual blockers. Then I scan for use of internal JDK APIs, add back Java EE pieces like JAXB that were removed in Java 11, and fix reflection that strong encapsulation now blocks. I check removed JVM flags, run the full test suite, roll out gradually, and only then adopt new features.
Read the full answer