■ Java Mastery Quiz
All 8 Topics · Interview-Ready Questions
Topic 1 OOP 4 Questions
Topic 2 Generics 3 Questions
Topic 3 Concurrency 4 Questions
Topic 4 Streams 4 Questions
Topic 5 Interfaces & Functional Prog 3 Questions
Topic 6 Exception Handling 3 Questions
Topic 7 Memory & Garbage Collection 3 Questions
Topic 8 Modern Java Features 3 Questions
■ How to use: Answer each question in your own words or with code examples. Answers are provided at the bottom of
each section — try answering before peeking!
Topic 1: OOP (Object-Oriented Programming)
Question 1
What are the four pillars of OOP? Briefly explain each one.
■ Hint: Think: what does each pillar protect, hide, share, or define?
Your Answer:
■ Answer Encapsulation — hiding internal state, exposing only via methods.
Inheritance — child class reuses parent's fields and methods.
Polymorphism — same method name behaves differently based on actual object.
Abstraction — hiding complexity behind interfaces/abstract classes.
Question 2
What is the difference between method overriding and method overloading?
■ Hint: Focus on: where it happens, parameters, and when it's resolved.
Your Answer:
■ Answer Overriding: child class redefines parent's method. Same name + same params. Resolved at runtime
(dynamic dispatch). Uses @Override annotation.
Overloading: same class, same method name but different parameters. Resolved at compile time.
Question 3
What is the difference between an abstract class and an interface? When would you choose
one over the other?
■ Hint: Java 8 changed interfaces — remember default methods!
Your Answer:
■ Answer Abstract class: can have abstract + concrete methods, constructors, instance variables. Single
inheritance only.
Interface: abstract methods + default/static methods (Java 8+). No constructors, no instance variables.
Multiple inheritance.
Choose abstract class when sharing base behavior/state. Choose interface to define a capability across
unrelated classes.
Question 4
Why should you always call super() in a child class constructor?
■ Hint: Think about: who owns the parent fields, validation, and private fields.
public class Animal {
private String name;
public Animal(String name) {
if(name == null) throw new IllegalArgumentException();
[Link] = name;
}
}
public class Dog extends Animal {
// What happens if you don't call super(name)?
}
Your Answer:
■ Answer 1. Parent owns its fields — child cannot set private fields directly.
2. Parent constructor may have validation logic — skipping super() skips validation.
3. If parent has no default constructor, Java forces you to call super() explicitly.
4. Clean responsibility — each class initializes only its own fields.
Topic 2: Generics
Question 1
What is the main purpose of generics in Java? What problem do they solve?
■ Hint: Think about what happens without generics — casting, runtime errors.
Your Answer:
■ Answer Generics provide type safety at compile time, eliminating the need for casting. Without generics,
collections use Object type — any type can be inserted causing ClassCastException at runtime. With
generics, type errors are caught at compile time.
Question 2
What is the difference between List and List? Give a use case for each.
■ Hint: Remember PECS: Producer Extends, Consumer Super.
Your Answer:
■ Answer List: upper bound. Accepts Number or subclasses (Integer, Double). Use when READING from list.
Cannot add to it (type unknown).
List: lower bound. Accepts Number or superclasses (Object). Use when WRITING to list. Cannot read as
specific type.
PECS rule: Producer Extends (give data), Consumer Super (receive data).
Question 3
What is wrong with this code and how would you fix it?
■ Hint: Look at what String is — can it be subclassed?
public static <T extends String> void print(T value) {
[Link](value);
}
Your Answer:
■ Answer String is a final class — nothing can extend it. So T can only ever be String. The bound is pointless.
Fix: public static void print(String value) — or if truly generic: public static void print(T value)
Topic 3: Concurrency
Question 1
What is a race condition? Give a real-world example and show how to fix it.
■ Hint: Think bank account — two threads, same balance.
private int balance = 1000;
public void withdraw(int amount) {
if (balance >= amount)
balance -= amount; // is this thread safe?
}
Your Answer:
■ Answer Race condition: two or more threads access shared data simultaneously, and the outcome depends on
thread scheduling.
Fix: use synchronized keyword, ReentrantLock, or AtomicInteger.
Note: volatile does NOT fix race conditions — it only ensures visibility, not atomicity of compound
operations like balance -= amount.
Question 2
What is the difference between synchronized and ReentrantLock? When would you prefer
ReentrantLock?
■ Hint: Think: tryLock, timeout, fairness, multiple conditions.
Your Answer:
■ Answer synchronized: simple, auto-releases, no extra features.
ReentrantLock: tryLock() (don't wait), tryLock(timeout), lockInterruptibly(), fairness
(first-come-first-served), multiple conditions.
Prefer ReentrantLock when you need: timeout on waiting, ability to give up if lock unavailable, fair
ordering, or multiple wait conditions.
Question 3
What does volatile do? Does it fix race conditions?
■ Hint: Visibility vs atomicity — these are different things.
private volatile boolean running = true;
private volatile int counter = 0;
// Are both usages correct?
Your Answer:
■ Answer volatile guarantees visibility — a write by one thread is immediately visible to all other threads. It does
NOT guarantee atomicity.
running = true/false is safe with volatile (single write, single read).
counter++ is NOT safe with volatile — it's 3 steps: read, modify, write.
Use AtomicInteger for thread-safe counters.
Question 4
What is CompletableFuture? How is it different from Future?
■ Hint: Think about chaining, callbacks, and blocking.
Your Answer:
■ Answer Future: basic async result container. get() blocks until done. No chaining, no callbacks, cannot combine.
CompletableFuture: supports chaining (thenApply, thenAccept), combining (thenCombine, allOf), error
handling (exceptionally), and non-blocking composition. Much more powerful for async pipelines.
Topic 4: Streams
Question 1
What is the difference between map() and flatMap()?
■ Hint: One-to-one vs one-to-many. Think nested lists.
List<List<String>> nested = [Link](
[Link]("A","B"), [Link]("C","D")
);
// How do you get a flat list: [A, B, C, D]?
Your Answer:
■ Answer map(): one-to-one transformation. Each element maps to exactly one output.
flatMap(): one-to-many transformation, then flattens. Each element can produce multiple outputs merged
into one stream.
Use flatMap when each element contains a collection inside it.
Question 2
What is the difference between findFirst() and findAny()? When is findAny() better?
■ Hint: Think parallel streams and performance.
Your Answer:
■ Answer findFirst(): always returns first element in encounter order. Predictable.
findAny(): returns any matching element. Unpredictable but faster.
findAny() is better with parallelStream() — no thread coordination needed. Whichever thread finds a
match first returns it immediately. Use findFirst() when order matters, findAny() when you just need any
match.
Question 3
What does [Link]() do? Write a query that groups employees by department
and counts them.
■ Hint: Think SQL: GROUP BY dept, COUNT(*)
List<Employee> employees = ...;
// Group by dept, count per dept
// Expected: {Engineering=3, Marketing=2, HR=2}
Your Answer:
■ Answer groupingBy() groups stream elements into a Map by a classifier function, like SQL GROUP BY.
Solution:
Map count = [Link]()
.collect([Link](
Employee::dept,
[Link]()
));
Question 4
Streams are lazy — what does this mean? Why is it beneficial?
■ Hint: When exactly do intermediate operations execute?
Stream<String> s = [Link]()
.filter(x -> { [Link](x); return true; })
.map(String::toUpperCase);
// Has anything printed yet?
Your Answer:
■ Answer Lazy means intermediate operations (filter, map, sorted) do not execute until a terminal operation
(collect, forEach, count) is called.
In the example — nothing prints until .collect() or similar is called.
Benefits: avoids unnecessary computation, enables short-circuit optimization (e.g. findFirst stops after
first match), more memory efficient for large datasets.
Topic 5: Interfaces & Functional Programming
Question 1
What is a functional interface? Name four built-in functional interfaces and describe what
each does.
■ Hint: [Link] package — what do they take and return?
Your Answer:
■ Answer Functional interface: exactly one abstract method. Enables lambda expressions.
Function: takes T, returns R. apply() method. For transformation.
Predicate: takes T, returns boolean. test() method. For filtering/conditions.
Consumer: takes T, returns void. accept() method. For side effects.
Supplier: takes nothing, returns T. get() method. For generating values.
Question 2
What is the difference between a lambda and a method reference? Convert this lambda to a
method reference.
■ Hint: When can you replace a lambda with ::?
[Link]()
.map(s -> [Link]())
.forEach(s -> [Link](s));
Your Answer:
■ Answer Lambda: anonymous function inline.
Method reference: shorthand when lambda just calls an existing method.
Converted:
[Link]()
.map(String::toUpperCase)
.forEach([Link]::println);
Types: ClassName::staticMethod, object::method, ClassName::instanceMethod, ClassName::new
Question 3
How do you combine two Predicates? Write an example that filters employees earning over
70000 AND older than 28.
■ Hint: Predicates have and(), or(), negate() methods.
Your Answer:
■ Answer Predicate highEarner = e -> [Link]() > 70000;
Predicate senior = e -> [Link]() > 28;
Predicate combined = [Link](senior);
[Link]()
.filter(combined)
.forEach(e -> [Link]([Link]()));
Topic 6: Exception Handling
Question 1
What is the difference between checked and unchecked exceptions? Give two examples of
each.
■ Hint: Which ones does the compiler force you to handle?
Your Answer:
■ Answer Checked: compiler forces you to handle or declare. For foreseeable problems.
Examples: IOException, SQLException, FileNotFoundException.
Unchecked (RuntimeException): compiler doesn't force handling. Programming mistakes.
Examples: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException.
Question 2
What is try-with-resources? Why is it better than using finally to close resources?
■ Hint: What happens to the resource automatically?
// Old way:
FileReader r = null;
try { r = new FileReader(path); }
catch(IOException e) { ... }
finally { if(r!=null) [Link](); }
// New way: rewrite using try-with-resources
Your Answer:
■ Answer try-with-resources automatically closes resources declared in () after try block, whether exception occurs
or not. Resource must implement AutoCloseable.
Better than finally because: no nested try-catch for close(), cleaner code, handles suppressed exceptions
properly.
try (FileReader r = new FileReader(path)) {
// use r
} catch (IOException e) { ... }
// r auto-closed here!
Question 3
What is the difference between throw and throws? When would you create a custom
exception?
■ Hint: One is inside a method, one is on the method signature.
Your Answer:
■ Answer throw: actually throws an exception instance inside a method body. Execution stops at throw.
throws: declares that a method might throw exceptions. Tells callers what to handle.
Create custom exception when: standard exceptions don't describe your business problem well, you
need extra fields (like amount, userId), or you want to create a clear hierarchy for your domain
(InsufficientFundsException, UserNotFoundException).
Topic 7: Memory & Garbage Collection
Question 1
What is the difference between Stack memory and Heap memory?
■ Hint: Think about what each stores and how long it lives.
public void method() {
int x = 10; // where?
String s = "Hello"; // where is reference? where is object?
Person p = new Person(); // where is reference? where is object?
}
Your Answer:
■ Answer Stack: stores local variables, method call frames, primitive values, and object references. Each thread
has its own stack. Auto managed (LIFO). Memory freed when method returns.
Heap: stores actual objects. Shared across all threads. Managed by GC. Lives until no references point
to object.
x=10: value in stack. s reference in stack, 'Hello' object in heap. p reference in stack, Person object in
heap.
Question 2
What are the most common causes of memory leaks in Java? Give two examples.
■ Hint: Java has GC — so how can leaks still happen?
Your Answer:
■ Answer Leaks happen when objects are referenced but never used — GC cannot collect them.
1. Static collections growing forever:
static Map cache = new HashMap(); — never cleared!
2. Listeners/callbacks never removed:
[Link](l); — never removeListener(l)!
3. Unclosed resources: connections, streams never closed.
4. Non-static inner classes holding implicit reference to outer class.
Question 3
What is the difference between Minor GC and Major GC? Which one causes more
performance impact?
■ Hint: Think Young Generation vs Old Generation.
Your Answer:
■ Answer Minor GC: collects Young Generation (Eden + Survivor spaces). Fast, frequent. Removes short-lived
objects. Low pause time.
Major GC (Full GC): collects Old Generation. Slow, infrequent. Causes 'Stop The World' pause —
application freezes during collection.
Major GC causes more performance impact. To minimize: avoid creating too many long-lived objects,
use appropriate GC (G1, ZGC for low latency).
Topic 8: Modern Java Features (Java 9–21+)
Question 1
What is a Record in Java? What does it auto-generate and what are its limitations?
■ Hint: Think: what boilerplate does it replace? What can't you do?
record Person(String name, int age, String email) {}
// What is auto-generated?
// What can you NOT do with this?
Your Answer:
■ Answer Record auto-generates: constructor, getters (name(), age(), email()), equals(), hashCode(), toString().
Limitations: immutable — no setters, all fields are final. Cannot extend another class (implicitly extends
Record). Cannot declare instance fields outside record header.
Can add: custom methods, static fields, compact constructors for validation.
Question 2
What are Sealed Classes? Why are they useful when combined with pattern matching
switch?
■ Hint: Think: exhaustiveness — compiler knows all possible subtypes.
sealed interface Shape permits Circle, Rectangle, Triangle {}
// Now write a switch that calculates area
// without needing a default case
Your Answer:
■ Answer Sealed classes restrict which classes can extend/implement them using 'permits'.
Combined with pattern matching switch: compiler knows ALL possible subtypes, so switch is exhaustive
— no default needed!
double area = switch(shape) {
case Circle c -> [Link] * [Link]() * [Link]();
case Rectangle r -> [Link]() * [Link]();
case Triangle t -> 0.5 * [Link]() * [Link]();
}; // no default — compiler verified all cases covered!
Question 3
What are Virtual Threads (Java 21)? How are they different from platform threads and when
should you use them?
■ Hint: Think: weight, memory, blocking behavior, scale.
// Platform threads
[Link](100);
// Virtual threads
[Link]();
// What is the key difference in practice?
Your Answer:
■ Answer Platform threads: heavy (~1MB each), backed by OS threads, limited to thousands.
Virtual threads: lightweight (few KB), managed by JVM, can have millions.
Key difference: when a virtual thread blocks (waiting for I/O, DB, API), the carrier (real) thread is freed to
run other virtual threads. Platform threads waste OS resources while blocked.
Use virtual threads for: high-concurrency I/O bound tasks (web servers, DB calls, API calls). NOT
beneficial for CPU-bound tasks.
■ All Topics Complete!
# Topic Questions Score
1 OOP (Object-Oriented Programming) 4 __ / 4
2 Generics 3 __ / 3
3 Concurrency 4 __ / 4
4 Streams 4 __ / 4
5 Interfaces & Functional Programming 3 __ / 3
6 Exception Handling 3 __ / 3
7 Memory & Garbage Collection 3 __ / 3
8 Modern Java Features (Java 9–21+) 3 __ / 3
TOTAL 27 __ / 27
Keep practicing — consistency beats intensity. Good luck! ■