JAVA BACKEND
INTERVIEW MASTER GUIDE
Fresher → 3 Years Experience | India Market
Service-Based • Product-Based • Mid-Level MNCs
Optimized for real selection, not academic learning.
🟢 FRESHER (0–1 yr) 🟠 1–2 YRS 🔴 2–3 YRS
SECTION 1 — CORE JAVA
Q1 What is the difference FRESHER
between JVM, JRE, and
JDK?
JDK (Java Development Kit): Full toolkit to write, compile, debug, and run Java. Contains JRE + compiler
(javac) + tools.
JRE (Java Runtime Environment): Needed only to RUN Java programs. Contains JVM + core libraries. No
compiler.
JVM (Java Virtual Machine): Executes bytecode. Platform-specific but bytecode is platform-independent.
Flow: Developer writes .java → JDK compiles to .class (bytecode) → JVM inside JRE runs it.
→ Example:
JDK = JRE + compiler + tools
JRE = JVM + libraries
JVM = bytecode executor
🎯 Why asked: Tests if candidate understands the Java ecosystem before writing any code. Tells you their
foundational clarity.
Q2 Explain JVM Architecture: 1-2 YRS
Class Loader, Memory
Areas, Execution Engine.
Class Loader: Loads .class files. 3 types: Bootstrap ([Link]), Extension (jre/lib/ext), Application (classpath).
Delegation: App→Ext→Bootstrap.
Memory Areas: Method Area (class data, static vars), Heap (objects, GC-managed), Stack (one per
thread, stores frames), PC Register (current instruction), Native Method Stack.
Execution Engine: Interpreter (line-by-line, slow), JIT Compiler (hot code → native, fast), GC (removes
unreferenced heap objects).
→ Example:
javac [Link] // creates [Link]
java Hello // JVM loads, verifies, executes
🎯 Why asked: Core JVM knowledge is asked in almost every 1–3 year interview. Weak answer here =
immediate red flag.
Q3 Where does each type of FRESHER
data live — Heap vs Stack?
Stack: Primitive local variables, method call frames, references (not objects). One stack per thread. Auto-
freed on method return.
Heap: All objects (new Keyword), instance variables. Shared across threads. Managed by GC.
String Pool: Special part of Heap. String literals go here. new String() goes to general heap.
Impact: Stack overflow → StackOverflowError. Heap overflow → OutOfMemoryError. Stack access is
faster than heap.
→ Example:
int x = 5; // Stack
String s = new String(); // Reference on Stack, Object on Heap
String lit = "hello"; // Reference on Stack, object in String Pool
🎯 Why asked: Tests memory awareness. Candidates who say 'everything is on the heap' fail immediately.
Q4 What is the Java Memory 2-3 YRS
Model (JMM)? What is
happens-before?
JMM defines rules about how threads interact through memory — what is visible to which thread and
when.
Without JMM: Thread A writes x=1, Thread B may still read x=0 due to CPU caches or compiler
reordering.
happens-before: A guarantee that write in one thread is visible to another. Key rules:
• A synchronized block exit happens-before the next thread enters the same block.
• volatile write happens-before volatile read of same variable.
• [Link]() happens-before any code in the started thread.
→ Example:
volatile boolean flag = false;
// Thread A: flag = true; // write
// Thread B: if(flag) { ... } // guaranteed to see true after volatile write
🎯 Why asked: Asked heavily in 2–3 year interviews. Tests if the candidate knows WHY synchronized and
volatile work, not just THAT they work.
Q5 OOP: Abstract Class vs FRESHER
Interface — when would
you choose one over the
other in a real project?
Abstract Class: Use when classes share state (instance variables) or common method implementations.
IS-A relationship.
Interface: Use when you want to define a CONTRACT — what a class can do, not how. Supports multiple
inheritance.
Real rule: If two classes share code → abstract class. If two unrelated classes share behaviour →
interface.
Java 8+: Interfaces can have default methods, which blurs the line — but interfaces still cannot have state
(fields).
→ Example:
// Interface: unrelated classes share behaviour
interface Printable { void print(); }
class Invoice implements Printable { ... }
class Report implements Printable { ... }
// Abstract: related classes share code
abstract class Animal { String name; void breathe() {...} }
class Dog extends Animal { void bark() {...} }
🎯 Why asked: Most asked OOP question. Candidates who say 'interface has no implementation' without
knowing default methods get rejected.
Q6 Explain method overriding 1-2 YRS
rules. What is covariant
return type?
Rules: Same method name, same parameters. Access modifier can only be WIDENED (not narrowed).
Return type can be same or a subtype (covariant).
Covariant return type: Overriding method can return a subclass of the parent's return type.
Cannot override: static methods (hidden, not overridden), final methods, private methods.
Exception rule: Override cannot throw new or broader checked exceptions than declared in parent.
→ Example:
class Animal { Animal create() { return new Animal(); } }
class Dog extends Animal {
@Override
Dog create() { return new Dog(); } // covariant: Dog is subtype of Animal
}
🎯 Why asked: Tests real OOP depth. 'Same signature' answers without mentioning covariant return or
exception rules = shallow knowledge.
Q7 What is the equals() and 1-2 YRS
hashCode() contract? Why
does it matter in
collections?
Contract: If [Link](b) is true, then [Link]() == [Link]() MUST be true.
Reverse NOT required: same hashCode does not mean equals() is true (hash collision is normal).
If you override equals() but NOT hashCode() → HashMap/HashSet will break silently.
Real bug: You create Employee with same id. Add one, try to find by another — it fails because hashCode
differs.
→ Example:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee)) return false;
return [Link] == ((Employee) o).id;
}
@Override
public int hashCode() { return [Link](id); }
🎯 Why asked: Critical question. HashMap internal working depends on this contract. If candidate doesn't know
this, they can't use HashMap correctly.
Q8 What is the difference FRESHER
between String,
StringBuffer, and
StringBuilder?
String: Immutable. Every modification creates a new object in heap. Thread-safe by nature (immutable).
StringBuffer: Mutable. Thread-safe (synchronized methods). Use in multi-threaded context.
StringBuilder: Mutable. NOT thread-safe. Faster than StringBuffer for single-threaded use.
Performance: String (worst for loops) < StringBuffer < StringBuilder (best for single-thread).
In a loop: String concatenation creates n objects. StringBuilder creates 1.
→ Example:
// BAD: creates 100 String objects
String s = ""; for(int i=0;i<100;i++) s += i;
// GOOD: creates 1 StringBuilder object
StringBuilder sb = new StringBuilder();
for(int i=0;i<100;i++) [Link](i);
🎯 Why asked: Tests immutability understanding and when to use which. String pool output questions are
extremely common.
Q9 String s1="Java"; String FRESHER
s2=new String("Java");
s1==s2? What about
[Link](s2)?
s1=="Java" literal → stored in String Pool.
s2=new String("Java") → creates new object on Heap (outside pool), even if same content exists.
s1 == s2 → FALSE: different memory addresses (one in pool, one in heap).
[Link](s2) → TRUE: compares content, not reference.
[Link]() → returns the pool reference, so s1 == [Link]() is TRUE.
→ Example:
String s1 = "Java";
String s2 = new String("Java");
[Link](s1 == s2); // false
[Link]([Link](s2)); // true
[Link](s1 == [Link]()); // true
🎯 Why asked: Extremely frequent tricky output question. Tests understanding of String Pool vs Heap memory.
Q10 How do you create a truly 1-2 YRS
immutable class in Java?
What are the edge cases?
Steps: (1) Make class final. (2) Make all fields private and final. (3) No setters. (4) Initialize in constructor.
(5) Deep copy mutable fields in constructor AND getter.
Edge case 1: If a field is a List or array, returning it directly breaks immutability — caller can modify the
object.
Edge case 2: If field is a mutable Date or custom object — must deep copy it.
Edge case 3: Reflection can break immutability — use SecurityManager (or accept the risk).
→ Example:
public final class Employee {
private final List<String> skills;
public Employee(List<String> skills) {
[Link] = new ArrayList<>(skills); // deep copy in
}
public List<String> getSkills() {
return [Link](skills); // safe out
}
}
🎯 Why asked: Very common question. Most candidates forget the deep copy requirement — that's the trap.
SECTION 2 — COLLECTIONS
Q11 Explain the internal 1-2 YRS
working of HashMap in
Java. How are elements
stored?
HashMap uses an array of buckets (Node[] table). Default capacity=16, load factor=0.75.
On put(key, value): hashCode() of key is computed → index = hash & (n-1) → value stored at that index.
Collision: Two keys with same index → Singly Linked List at that bucket (chaining).
Java 8+: When linked list at one bucket >= 8 entries AND total size >= 64 → converts to Red-Black Tree
(O(log n) lookup).
Resize (rehashing): When size > capacity * loadFactor → array doubles, all entries rehashed. Expensive
operation.
→ Example:
// hashCode determines bucket; equals resolves collision
[Link]("name", "Alice");
// 1. "name".hashCode() → int
// 2. index = hash & 15 (for size 16)
// 3. store Node(key, value, next) at index
// 4. if collision → append to linked list
🎯 Why asked: The single most asked Collections question in India interviews. Every level asks this. Must know
RB-tree threshold.
Q12 Why was 2-3 YRS
ConcurrentHashMap
introduced when Hashtable
already existed?
Hashtable: Synchronizes ENTIRE map on every put/get. Only one thread can access the whole map at a
time. Massive bottleneck.
ConcurrentHashMap (Java 7): Divided map into 16 segments. Each segment has its own lock. 16 threads
can write simultaneously.
ConcurrentHashMap (Java 8): Removed segments. Uses CAS (Compare-And-Swap) for concurrent
writes. Synchronized only at bucket level on collision.
Null keys/values: Hashtable allows null. ConcurrentHashMap does NOT allow null key/value (ambiguity in
concurrent context).
Read operations: In CHM, reads are completely lock-free in Java 8+.
→ Example:
ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<>();
[Link]("a", 1); // CAS-based, no full lock
[Link]("b", k -> 2); // atomic operation
🎯 Why asked: Tests deep concurrency knowledge. Saying 'CHM is thread-safe' without explaining HOW =
rejected at product companies.
Q13 Comparator vs Comparable 1-2 YRS
— implement descending
salary sort for Employee.
Comparable: Natural ordering. Class implements it (compareTo). Only one sort order possible.
Comparator: External ordering. Separate class/lambda. Multiple sort orders possible.
Use Comparable when class has one obvious natural order (Integer, String).
Use Comparator when: you don't own the class, need multiple orderings, or lambda/method reference is
cleaner.
→ Example:
// Comparable (natural order by id)
class Employee implements Comparable<Employee> {
int id; String name; double salary;
public int compareTo(Employee e) { return [Link]([Link], [Link]); }
}
// Comparator (descending salary, external)
List<Employee> list = ...;
[Link]([Link](Employee::getSalary).reversed());
// Multi-field: salary desc, then name asc
[Link]([Link](Employee::getSalary).reversed()
.thenComparing(Employee::getName));
🎯 Why asked: Always comes with a coding task. Candidates who explain theory but can't write the lambda get
rejected.
Q14 What is fail-fast vs fail-safe 1-2 YRS
iteration? When does
ConcurrentModificationExc
eption occur?
Fail-fast: Iterator uses a modCount counter. On modification during iteration (add/remove from another
thread or same thread), modCount changes → ConcurrentModificationException thrown immediately.
Fail-safe: Iterator works on a copy of the collection (e.g., CopyOnWriteArrayList). No exception but sees
stale data.
Real cause: Removing from a List while iterating using enhanced for-loop.
Fix: Use Iterator's remove(), use removeIf(), or use CopyOnWriteArrayList.
→ Example:
// WRONG: ConcurrentModificationException
for (String s : list) { if ([Link]("x")) [Link](s); }
// CORRECT: use [Link]()
Iterator<String> it = [Link]();
while ([Link]()) { if ([Link]().equals("x")) [Link](); }
// ALSO CORRECT: Java 8
[Link](s -> [Link]("x"));
🎯 Why asked: Very common trap question. Tests real-world collection usage. Most candidates know the
exception name but not the fix.
SECTION 3 — JAVA 8+ (Streams, Lambdas, Optional)
Q15 What is a Functional FRESHER
Interface? Write one to sum
two numbers.
A Functional Interface has exactly ONE abstract method. Can have default and static methods.
@FunctionalInterface annotation is optional but recommended — compiler enforces the single-abstract-
method rule.
Built-in: Predicate<T> (T→boolean), Function<T,R> (T→R), Supplier<T> (→T), Consumer<T> (T→void),
BiFunction<T,U,R>.
Lambda expressions are just a concise way to implement a Functional Interface.
→ Example:
@FunctionalInterface
interface Calculator { int operate(int a, int b); }
Calculator sum = (a, b) -> a + b;
Calculator mult = (a, b) -> a * b;
[Link]([Link](3, 4)); // 7
[Link]([Link](3, 4)); // 12
🎯 Why asked: Entry-level Java 8 question. Tests if candidate can go from definition to working code instantly.
Q16 What is the difference 1-2 YRS
between intermediate and
terminal operations in
Streams?
Intermediate: Return a new Stream. Lazy — NOT executed until a terminal operation is called. Examples:
filter, map, sorted, distinct, limit, flatMap.
Terminal: Trigger the pipeline execution and produce a result. Examples: collect, forEach, count, reduce,
findFirst, anyMatch.
Streams are lazy: filter+map do nothing until collect/forEach is called. Only elements that pass each stage
are processed.
Short-circuiting: findFirst(), anyMatch(), limit() can stop the pipeline early.
→ Example:
List<String> names = [Link]("Alice","Bob","Anna","Charlie");
long count = [Link]()
.filter(n -> [Link]("A")) // intermediate
.map(String::toUpperCase) // intermediate
.count(); // terminal → 2
🎯 Why asked: Tests Stream pipeline understanding. Candidates who don't know lazy evaluation can't explain
performance implications.
Q17 What are the pitfalls of 2-3 YRS
parallelStream() in a web
application?
parallelStream() uses the common ForkJoinPool (default: CPU cores - 1). In a web app, all requests share
this pool.
Pitfall 1: One slow parallel task can starve the entire ForkJoinPool, affecting all requests.
Pitfall 2: Thread safety — shared mutable state causes race conditions.
Pitfall 3: Overhead. Parallel is slower than sequential for small collections.
When to use: CPU-intensive work on large datasets (>10k items) where order doesn't matter and no
shared state.
Better alternative: Use a dedicated ExecutorService with bounded thread pool instead of shared
ForkJoinPool.
→ Example:
// DANGER in web app: uses shared ForkJoinPool
[Link]().map(heavyOp).collect(toList());
// SAFER: custom pool
ForkJoinPool pool = new ForkJoinPool(4);
[Link](() -> [Link]().map(heavyOp).collect(toList())).get();
🎯 Why asked: Distinguishes candidates who understand concurrency from those who just use parallelStream()
for speed.
Q18 What is Optional in Java 8? 1-2 YRS
What are the correct and
wrong ways to use it?
Optional<T> is a container that may or may not hold a value. Replaces null checks when used correctly.
WRONG: if([Link]() != null) — defeats the purpose; get() throws NoSuchElementException if empty.
WRONG: Optional as a method parameter — never use Optional as a field or parameter, only as return
type.
CORRECT: Use isPresent()/get() pair, or better: orElse(), orElseGet(), ifPresent(), map(), flatMap().
→ Example:
// WRONG
Optional<User> opt = findUser(id);
if ([Link]() != null) { ... } // NoSuchElementException risk!
// CORRECT
findUser(id)
.map(User::getEmail)
.orElse("no-email@[Link]");
// orElseGet (lazy - only called if empty)
findUser(id).orElseGet(() -> createDefaultUser());
🎯 Why asked: Tests if candidate actually uses Optional correctly. Most just wrap returns in [Link]() and still
call .get() unsafely.
SECTION 4 — MULTITHREADING & CONCURRENCY
Q19 What is a race condition? 2-3 YRS
Give a real backend API
example.
Race condition: Two or more threads access and modify shared data concurrently, and the outcome
depends on execution order.
Classic backend example: Wallet debit — two API requests arrive simultaneously for the same user. Both
read balance=1000, both deduct 500, both write 500. Final balance = 500 instead of 0. Money is created
from thin air.
Prevention: synchronized block, AtomicInteger, ReentrantLock, database-level locking (SELECT FOR
UPDATE), or optimistic locking (@Version in JPA).
→ Example:
// BROKEN: race condition
int balance = [Link](); // Thread A and B both read 1000
if (balance >= amount) [Link](balance - amount); // both write 500
// FIXED: synchronized
public synchronized void debit(int amount) {
if (balance >= amount) balance -= amount;
}
// OR: AtomicInteger for simple counters
AtomicInteger balance = new AtomicInteger(1000);
[Link](-amount); // atomic operation
🎯 Why asked: Real backend scenario. Tests if candidate can identify concurrency bugs in API code, not just
define race condition.
Q20 synchronized keyword — 1-2 YRS
method vs block. What is
the lock object in each
case?
Synchronized instance method: Lock is the current object instance (this). All synchronized instance
methods of the same object are mutually exclusive.
Synchronized static method: Lock is the Class object ([Link]). Separate from instance locks.
Synchronized block: You specify the lock object explicitly. Finer-grained control.
Key insight: Two threads calling different synchronized methods on the SAME object block each other
(same lock). On DIFFERENT objects — no blocking.
→ Example:
// Instance method lock = this
public synchronized void methodA() { ... }
// Static method lock = [Link]
public static synchronized void increment() { ... }
// Block: fine-grained, custom lock object
private final Object lock = new Object();
public void doWork() {
synchronized(lock) { /* only critical section locked */ }
// rest of method is not locked → better performance
}
🎯 Why asked: This is asked in multiple variations. Candidates often confuse instance vs class-level locks.
Q21 What is a deadlock? How 2-3 YRS
do you prevent it?
Deadlock: Thread A holds Lock1 and waits for Lock2. Thread B holds Lock2 and waits for Lock1. Both
wait forever.
4 conditions (Coffman): Mutual exclusion, Hold and wait, No preemption, Circular wait.
Prevention strategies:
1. Always acquire locks in same ORDER across all threads.
2. Use tryLock() with timeout (ReentrantLock) — don't wait forever.
3. Use one coarse lock instead of many fine-grained locks where possible.
4. Use concurrent data structures that don't require explicit locking.
→ Example:
// DEADLOCK risk: different order
// Thread A: lock(account1) then lock(account2)
// Thread B: lock(account2) then lock(account1)
// FIX: always lock in consistent order
void transfer(Account from, Account to, int amt) {
Account first = [Link] < [Link] ? from : to;
Account second = [Link] < [Link] ? to : from;
synchronized(first) { synchronized(second) {
[Link](amt); [Link](amt);
}}
}
🎯 Why asked: Classic interview question at every level. Must be able to both explain and show code fix.
Q22 wait() vs sleep() — what is 1-2 YRS
the core difference?
sleep(): Thread pauses for specified time. Does NOT release the lock. Belongs to Thread class.
wait(): Thread pauses AND RELEASES the lock. Waits until notify()/notifyAll() is called. Belongs to Object
class.
wait() must be called inside synchronized block (otherwise IllegalMonitorStateException).
sleep() can be called anywhere.
Use case: wait/notify for producer-consumer coordination. sleep() for simple time delays.
→ Example:
// wait() — releases lock, waits for signal
synchronized(lock) {
while ([Link]()) {
[Link](); // releases lock, thread suspends
}
process([Link]());
}
// notify() — wakes up a waiting thread
synchronized(lock) {
[Link](item);
[Link]();
}
🎯 Why asked: wait/sleep distinction is asked in nearly every multithreading interview. The 'releases lock' part is
the key answer.
Q23 What is ThreadLocal and 2-3 YRS
when would you actually
use it?
ThreadLocal: Provides per-thread storage. Each thread gets its own isolated copy of the variable.
Real use case 1: Storing the logged-in user context per request in a web app (Spring uses this for
SecurityContextHolder).
Real use case 2: Database connection per thread in connection-per-thread models.
Real use case 3: SimpleDateFormat (not thread-safe) — each thread gets its own instance.
CRITICAL: Must call remove() after use in thread pool environments, or else memory leak (thread reuse
retains old values).
→ Example:
private static ThreadLocal<User> currentUser = new ThreadLocal<>();
// In request interceptor (runs per thread):
[Link](authenticatedUser);
// Anywhere in the same thread:
User user = [Link]();
// MUST clean up (thread pool reuses threads!)
[Link](); // typically in finally or interceptor afterCompletion
🎯 Why asked: Tests real-world threading knowledge. Knowing about memory leak in thread pools separates
good candidates.
SECTION 5 — SPRING BOOT
Q24 What is IoC and FRESHER
Dependency Injection?
Explain with a real project
example.
IoC (Inversion of Control): The Spring container creates and manages objects, instead of you creating
them with new.
DI (Dependency Injection): Spring injects required dependencies (other beans) into your class —
constructor, setter, or field injection.
Constructor injection: Preferred. Makes dependencies mandatory, testable, immutable.
Field injection (@Autowired on field): Convenient but bad — can't easily mock in tests, hides
dependencies.
Real project: OrderService needs PaymentService. Without IoC: OrderService creates new
PaymentService() — tightly coupled. With IoC: Spring injects PaymentService — loosely coupled, easily
testable.
→ Example:
// PREFERRED: constructor injection
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
[Link] = paymentService;
}
// Spring automatically injects PaymentService bean
}
🎯 Why asked: Every Spring interview starts here. Candidate must know WHY constructor > field injection for
real projects.
Q25 Explain Spring Bean 1-2 YRS
lifecycle — from
instantiation to destruction.
1. Instantiation: Spring creates bean using constructor.
2. Populate properties: @Autowired dependencies injected.
3. BeanNameAware / BeanFactoryAware callbacks (if implemented).
4. @PostConstruct / afterPropertiesSet(): Initialization logic runs.
5. Bean is READY — in service.
6. @PreDestroy / destroy(): Cleanup runs when context is closed.
Practical: Use @PostConstruct to load config/cache on startup. Use @PreDestroy to close DB
connections.
→ Example:
@Component
public class CacheLoader {
@PostConstruct
public void init() {
// runs after bean created and deps injected
loadCacheFromDB();
}
@PreDestroy
public void cleanup() {
// runs before bean destroyed
[Link]();
}
}
🎯 Why asked: Asked at 1–2 year level. Tests real understanding of Spring lifecycle, not just 'instantiation and
destruction'.
Q26 @Transactional — explain 2-3 YRS
propagation. What happens
if you call a @Transactional
method from within the
same class?
REQUIRED (default): Use existing transaction or create new one.
REQUIRES_NEW: Always create new transaction. Suspends existing one. Use when you want audit log
saved even if main tx rolls back.
NESTED: Creates savepoint within existing transaction. Inner can rollback without affecting outer.
Self-invocation problem: Calling a @Transactional method from another method in the SAME class
bypasses Spring's proxy → transaction NOT applied. This is one of the most common Spring bugs.
Fix: Inject self-reference, use [Link](), or restructure to call from another bean.
→ Example:
@Service
public class UserService {
public void register(User u) {
save(u); // SELF-INVOCATION: @Transactional on save() is IGNORED!
}
@Transactional // this does NOTHING when called from register()
public void save(User u) { [Link](u); }
}
// FIX: inject self or restructure
@Autowired private UserService self;
[Link](u); // goes through proxy → @Transactional works
🎯 Why asked: The self-invocation trap is asked in product company interviews specifically. Most candidates
don't know this bug.
Q27 What does 1-2 YRS
@SpringBootApplication
consist of? What is auto-
configuration?
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan.
@Configuration: This class is a Spring config class (can define @Bean methods).
@ComponentScan: Scans the current package and sub-packages for @Component, @Service,
@Repository, @Controller.
@EnableAutoConfiguration: Reads [Link] (or [Link] in Boot 3.x). For each
library on classpath, applies default configuration automatically.
Example: Add spring-boot-starter-data-jpa → auto-config creates DataSource, EntityManagerFactory,
TransactionManager beans automatically.
→ Example:
// Without Spring Boot auto-config:
// You must define DataSource, EntityManager, TransactionManager manually
// With @EnableAutoConfiguration:
// Just add in [Link]:
// [Link]=jdbc:mysql://localhost/db
// [Link]=root
// Spring Boot creates all JPA beans automatically
🎯 Why asked: Interviewer wants to know if the candidate understands the magic, not just uses it blindly.
Q28 What is Spring AOP? Write 2-3 YRS
a logging aspect for all
service methods.
AOP (Aspect-Oriented Programming): Add cross-cutting concerns (logging, security, transactions) to
beans without modifying their code.
@Aspect: Marks class as aspect. @Pointcut: Expression defining WHICH methods to intercept.
Advice types: @Before (before method), @After (after method, always), @AfterReturning (after success),
@AfterThrowing (after exception), @Around (full control, most powerful).
@Transactional is itself implemented using AOP — Spring wraps your method in a proxy with transaction
logic.
→ Example:
@Aspect @Component
public class LoggingAspect {
@Around("execution(* [Link].*.*(..))") // all service methods
public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = [Link]();
Object result = [Link](); // call actual method
long time = [Link]() - start;
[Link]("{} executed in {}ms", [Link](), time);
return result;
}
}
🎯 Why asked: AOP is frequently missing from candidates' Spring knowledge. It's tested at 2-3 year level.
@Around is the most important advice type.
SECTION 6 — REST APIs & WEB LAYER
Q29 What is the difference FRESHER
between @RequestParam,
@PathVariable, and
@RequestBody?
@PathVariable: Extracts value from URI path. Used for resource identity. Example: /users/{id}
@RequestParam: Extracts from query string. Optional, with defaults. Example: /users?page=1&size=20
@RequestBody: Deserializes JSON request body into object. Used in POST/PUT. Requires Jackson on
classpath.
Rule of thumb: @PathVariable for IDs, @RequestParam for filters/pagination, @RequestBody for data
payloads.
→ Example:
@GetMapping("/users/{id}") // GET /users/42
public User getUser(@PathVariable Long id) { ... }
@GetMapping("/users") // GET /users?page=0&size=10
public Page<User> list(
@RequestParam(defaultValue="0") int page,
@RequestParam(defaultValue="10") int size) { ... }
@PostMapping("/users") // POST /users {body: {...}}
public User create(@RequestBody @Valid UserRequest req) { ... }
🎯 Why asked: Always asked with a 'write the endpoint' follow-up. Must be able to code instantly, not just
explain.
Q30 Which HTTP methods are 1-2 YRS
idempotent? What does
idempotent mean in
practice?
Idempotent: Calling the operation N times produces the same result as calling it once.
GET: Idempotent (reading doesn't change state).
PUT: Idempotent (replace entire resource — PUT user/1 with same body always gives same state).
DELETE: Idempotent (deleting something twice — second call finds nothing, state is same: not exists).
PATCH: NOT strictly idempotent (e.g., incrementing a field by 1 gives different result each time).
POST: NOT idempotent (each call creates a new resource).
Safe methods (no side effects): GET, HEAD, OPTIONS.
→ Example:
// Idempotent: PUT replaces, calling twice = same result
PUT /users/1 { name: "Alice" } // result: user 1 has name Alice
PUT /users/1 { name: "Alice" } // result: same
// Non-idempotent: POST creates new record
POST /orders // creates order 1
POST /orders // creates order 2 (different result!)
🎯 Why asked: Idempotency is asked in payment/fintech interviews and any microservices design question.
Q31 How does Spring Boot 1-2 YRS
handle exceptions
globally? Write a
@ControllerAdvice.
@ControllerAdvice: A global exception handler that applies to ALL controllers.
@ExceptionHandler: Method inside @ControllerAdvice that handles a specific exception type.
@RestControllerAdvice = @ControllerAdvice + @ResponseBody (returns JSON automatically).
Best practice: Create a standard ErrorResponse DTO. Return consistent structure for all errors.
Validation errors come as MethodArgumentNotValidException → extract field errors from it.
→ Example:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
return new ErrorResponse(404, [Link]());
}
@ExceptionHandler([Link])
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
String msg = [Link]().getFieldErrors()
.stream().map(FieldError::getDefaultMessage).collect(joining(", "));
return new ErrorResponse(400, msg);
}
}
🎯 Why asked: Every Spring Boot project needs this. Code must be written live in interviews. Know the
MethodArgumentNotValidException extraction.
SECTION 7 — JPA / HIBERNATE
Q32 What is the N+1 query 1-2 YRS
problem? Is it caused by
EAGER or LAZY loading?
N+1: When fetching N parent entities results in N additional queries to fetch child entities (1 query for
parents + N queries for children).
It is caused by LAZY loading — when you iterate over parents and access a lazy collection, Hibernate fires
1 query per parent.
EAGER loading fetches everything upfront in fewer queries but loads data you may never need.
Fix options: @EntityGraph, JOIN FETCH in JPQL, @BatchSize(size=25), or DTO projection with @Query.
→ Example:
// N+1 problem: 1 query for users, then 1 per user for orders
List<User> users = [Link](); // 1 query
[Link](u -> [Link]().size()); // N queries!
// FIX 1: JOIN FETCH
@Query("SELECT u FROM User u JOIN FETCH [Link]")
List<User> findAllWithOrders();
// FIX 2: EntityGraph
@EntityGraph(attributePaths = {"orders"})
List<User> findAll();
🎯 Why asked: The most asked JPA question in product-company interviews. Must know the fix, not just the
problem.
Q33 What is optimistic vs 2-3 YRS
pessimistic locking in
JPA? When to use each?
Optimistic Locking: Assumes conflicts are rare. Uses @Version field. Before UPDATE, checks version
matches. If not → OptimisticLockException. No DB lock held.
Pessimistic Locking: Assumes conflicts are common. Holds a DB-level lock (SELECT FOR UPDATE).
Other transactions must wait.
Use optimistic when: reads >> writes, low contention (e.g., profile updates).
Use pessimistic when: data contention is high, can't afford retry (e.g., seat booking, inventory deduction).
→ Example:
// Optimistic: @Version auto-checked on save
@Entity public class Product {
@Id Long id;
int stock;
@Version int version; // auto-incremented by Hibernate on each save
}
// Pessimistic: DB-level row lock
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE [Link] = :id")
Product findByIdForUpdate(@Param("id") Long id);
🎯 Why asked: Asked in fintech, e-commerce, and any system with concurrent writes. Must be able to explain
trade-offs.
SECTION 8 — SQL & DATABASE
Q34 Write SQL to find the 2nd FRESHER
highest salary. Generalize
for Nth highest.
Multiple approaches: Subquery, DENSE_RANK(), LIMIT+OFFSET.
DENSE_RANK() is the cleanest approach and handles ties correctly.
LIMIT+OFFSET: Simple but fails on ties (may return wrong result).
Interviewers prefer the window function approach as it shows SQL maturity.
→ Example:
-- DENSE_RANK approach (handles ties, most correct)
SELECT name, salary FROM (
SELECT name, salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM Employee
) ranked
WHERE rnk = 2;
-- Nth highest (parameterized version)
-- Replace rnk = 2 with rnk = N
-- Subquery approach (simpler but verbose)
SELECT MAX(salary) FROM Employee
WHERE salary < (SELECT MAX(salary) FROM Employee);
🎯 Why asked: Nth salary is asked in 70%+ of Java backend interviews with SQL. Must know at least 2
approaches.
Q35 What is indexing? When 1-2 YRS
does an index NOT help or
actually hurt?
Index: B-tree data structure that speeds up SELECT lookups. Without index, DB does full table scan O(n).
When it helps: Columns in WHERE, JOIN, ORDER BY, GROUP BY with high cardinality (many distinct
values).
When it HURTS or doesn't help:
1. INSERT/UPDATE/DELETE are slower — index must be updated on every write.
2. Low cardinality columns (e.g., gender: M/F) — index skipped by optimizer.
3. LIKE '%text%' (leading wildcard) — can't use B-tree index.
4. Functions on indexed column: WHERE YEAR(created_at)=2024 — index not used.
→ Example:
-- Index used: high cardinality, no function
CREATE INDEX idx_email ON users(email);
SELECT * FROM users WHERE email = 'a@[Link]'; -- uses index
-- Index NOT used: function on column
SELECT * FROM users WHERE YEAR(created_at) = 2024; -- full scan!
-- FIX: use range instead
SELECT * FROM users WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';
🎯 Why asked: Tests SQL maturity. Saying 'index makes queries faster' without knowing the downsides =
shallow answer.
Q36 Explain ACID properties. 1-2 YRS
How does Spring
@Transactional ensure
them?
Atomicity: All operations in transaction succeed or all fail. @Transactional rollback on exception ensures
this.
Consistency: DB moves from one valid state to another. Enforced by DB constraints + application logic.
Isolation: Transactions don't see each other's uncommitted changes. Controlled by isolation level
(READ_COMMITTED default).
Durability: Committed data survives crashes. Handled by DB (WAL logs, fsync).
@Transactional(rollbackOn=[Link]): By default only rolls back on RuntimeException. Must
specify for checked exceptions.
→ Example:
@Transactional(rollbackFor = [Link])
public void transfer(Long from, Long to, BigDecimal amt) throws Exception {
Account src = [Link](from).orElseThrow();
Account dest = [Link](to).orElseThrow();
[Link](amt); // if this succeeds
[Link](amt); // but THIS throws → both rolled back (Atomicity)
}
🎯 Why asked: ACID without understanding how Spring implements it = textbook answer. Must link to
@Transactional behavior.
SECTION 9 — MICROSERVICES (Basics for 0–3 Years)
⚠️SCOPE NOTE: Questions in this section are appropriate for 2–3 year candidates targeting product
companies. For service-based (TCS/Infosys) or fresher roles, focus on Sections 1–8. Advanced topics
like Saga, CQRS, and multi-tenancy are 4–7 year territory — avoid studying those unless your role
specifically requires it.
Q37 Microservices vs Monolith 2-3 YRS
— what are the real
downsides of
microservices?
Monolith: Simple to develop, test, deploy. Hard to scale individual parts. Large codebase becomes slow.
Microservices benefits: Independent deployment, independent scaling, tech flexibility, team autonomy.
REAL downsides (interviewers love this):
1. Distributed system complexity — network failures, latency.
2. Data consistency — no single transaction across services.
3. Operational overhead — need Kubernetes, service mesh, distributed tracing.
4. Debugging is harder — a request spans 5 services, which one failed?
5. Over-engineering for small teams — microservices with 2 developers is a nightmare.
🎯 Why asked: Candidates who only list benefits without knowing trade-offs fail immediately. Interviewers want
maturity.
Q38 What is a Circuit Breaker? 2-3 YRS
Explain the three states
with a real example.
Circuit Breaker (Resilience4j): Protects a service from calling a failing downstream service repeatedly.
CLOSED: Normal operation. Calls pass through. Monitors failure rate.
OPEN: Failure rate exceeded threshold → all calls blocked immediately → fallback returned. No actual
calls made.
HALF-OPEN: After wait duration, allows limited test calls. If they succeed → back to CLOSED. If they fail
→ back to OPEN.
Real use: OrderService calls InventoryService. If Inventory is down, instead of 30-second timeouts, circuit
opens immediately → user gets cached response or error instantly.
→ Example:
@CircuitBreaker(name = "inventoryService", fallbackMethod = "fallback")
public Product getProduct(Long id) {
return [Link](id); // protected call
}
public Product fallback(Long id, Exception e) {
return [Link](id); // fallback
}
# [Link]
[Link]:
failureRateThreshold: 50
waitDurationInOpenState: 10s
🎯 Why asked: Practical resilience pattern. Must know the 3 states and must be able to write the
@CircuitBreaker annotation.
SECTION 10 — REAL-WORLD SCENARIO QUESTIONS
HOW TO ANSWER: For every scenario: state the Problem clearly, identify Key Concepts, give the
Approach, and mention Trade-offs. Never jump to code without explaining the approach first.
S1 Your API response time spiked from 200ms to
8 seconds under load. How do you debug and
fix it?
Step 1 — Isolate: Is it all endpoints or one? Check APM (Datadog, New Relic, Actuator /metrics).
Step 2 — DB first: Check slow query logs. Is Hibernate firing N+1 queries? Use EXPLAIN ANALYZE on
slow queries.
Step 3 — Thread pool: Is ExecutorService queue full? Are DB connection pool threads exhausted
(HikariCP maxPoolSize too low)?
Step 4 — GC: Are Full GCs causing stop-the-world pauses? Check GC logs or JFR.
Step 5 — External calls: Is a downstream microservice slow? Add timeouts + circuit breaker.
Common fix: Add index to queried column. Increase HikariCP pool. Add caching (Redis). Fix N+1 with
JOIN FETCH.
🔑 Key Concepts: N+1 queries, HikariCP connection pool, GC tuning, caching, circuit breaker, query
optimization
S2 How do you prevent duplicate payment
submissions (same user clicks pay twice)?
Idempotency key: Client sends a unique idempotencyKey (UUID) with each payment request.
Server: Before processing, check if this key was already processed (Redis or DB lookup).
If key exists → return previous result immediately without reprocessing.
If key is new → process payment, store key + result with TTL.
DB: Add UNIQUE constraint on idempotencyKey column as a safety net.
Frontend: Disable pay button immediately on click. Re-enable only on explicit failure.
🔑 Key Concepts: Idempotency keys, Redis, unique constraints, distributed systems, API design
S3 Your Spring Boot app is getting
OutOfMemoryError in production after
running for several hours.
Step 1: Capture heap dump. Add -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp to
JVM args.
Step 2: Analyze heap dump with Eclipse MAT or VisualVM. Find the largest object type consuming
memory.
Common causes: (a) ThreadLocal values not removed in thread pool → ThreadLocal leak. (b) Static
collection growing unboundedly. (c) Unclosed InputStream/connection. (d) Cache growing without eviction
policy.
Step 3: If Old Gen fills up → objects are being tenured → check if you're holding references too long.
Step 4: Switch GC to G1GC (-XX:+UseG1GC) for better large heap management.
🔑 Key Concepts: Heap dump analysis, ThreadLocal leak, GC tuning, memory profiling, object lifecycle
S4 How do you handle 10,000 concurrent users
hitting your Spring Boot API?
Application level: Ensure endpoints are stateless. Use connection pooling (HikariCP maxPoolSize=20–50).
Caching: Cache frequently read, rarely changing data in Redis. Avoid hitting DB on every request.
Async processing: Move heavy work off the request thread using @Async or a message queue (Kafka).
DB level: Read replicas for read-heavy workloads. Proper indexing. Pagination — never return unbounded
results.
Infrastructure: Horizontal scaling (multiple instances) behind a load balancer. K8s HPA based on
CPU/memory.
Rate limiting: Protect against abuse using Bucket4j or API gateway rate limiting.
🔑 Key Concepts: Connection pooling, caching, async, horizontal scaling, rate limiting, stateless design
S5 How do you implement role-based access
control? A manager can see all orders, a
customer only their own.
Spring Security: Define roles (ROLE_MANAGER, ROLE_CUSTOMER) stored in DB or JWT claims.
@PreAuthorize: Method-level authorization. @PreAuthorize("hasRole('MANAGER')").
Data-level filter: After authentication, if CUSTOMER → add WHERE user_id = #{[Link]} to query.
Manager → no filter.
JPA: Pass authenticated userId from SecurityContext into repository query.
Never trust client-sent userId in body — always get from SecurityContext (Principal).
🔑 Key Concepts: Spring Security, JWT, @PreAuthorize, SecurityContext, data-level authorization
S6 OrderService calls InventoryService and
PaymentService. InventoryService succeeds
but PaymentService fails. How do you handle
this?
This is a distributed transaction problem. Options:
Option A (2PC/XA): Overkill and creates tight coupling. Avoid in microservices.
Option B (Saga pattern - Choreography): Each service emits events. On PaymentService failure → emit
OrderCancelled event → InventoryService listens and reverses stock (compensating transaction).
Option C (Saga - Orchestration): OrderOrchestrator drives the workflow. On payment failure, orchestrator
explicitly calls [Link]().
Ensure all Saga steps are idempotent — retries must not double-deduct or double-reserve.
🔑 Key Concepts: Saga pattern, compensating transactions, event-driven, idempotency, eventual consistency
S7 Your REST API is getting CORS errors in the
browser. How do you debug and fix it?
CORS (Cross-Origin Resource Sharing): Browser blocks JS from origin A calling API at origin B by default.
Fix in Spring Boot: @CrossOrigin(origins = "[Link] on controller, or global config via
CorsRegistry.
Common mistake: Adding CORS config after Spring Security filter — Security blocks request before
CORS headers are set.
Correct order: CORS filter must run BEFORE Spring Security. Use CorsConfigurationSource in
SecurityFilterChain.
Preflight: Browser sends OPTIONS request first. Make sure your CORS config allows OPTIONS or Spring
Security permits it.
🔑 Key Concepts: CORS, Spring Security filter chain order, HTTP OPTIONS, preflight requests
S8 Your @Scheduled job runs fine locally but
fails in production with multiple instances.
Problem: @Scheduled runs on ALL instances. If you have 3 pods, the job runs 3 times simultaneously.
Solution 1: ShedLock library — inserts a lock record in DB/Redis before job runs. Other instances see the
lock and skip.
Solution 2: Use a dedicated single-instance scheduler service.
Solution 3: Move scheduled work to a message queue — only one consumer processes each message.
Never rely on only one instance always being alive — it will restart at the worst time.
🔑 Key Concepts: Distributed locking, ShedLock, stateless deployments, Kubernetes, message queues
S9 How do you implement pagination correctly in
a Spring Boot API that returns millions of
rows?
Never fetch all data and paginate in memory — this is the #1 mistake.
Use Spring Data Pageable: Pass Pageable to repository, use Page<T> return type.
SQL level: LIMIT + OFFSET (simple but slow for large offsets — DB scans all skipped rows).
Cursor-based pagination (better for large data): Use id > lastSeenId LIMIT 20. No offset, constant time.
Always return total count only if needed — COUNT(*) on large tables is expensive. Use hasNext flag
instead.
🔑 Key Concepts: Spring Data Pageable, cursor vs offset pagination, SQL LIMIT/OFFSET, performance
S10 How do you debug a slow Hibernate/JPA
query in production?
Step 1: Enable SQL logging: [Link]-sql=true and [Link].format_sql=true.
Step 2: Check for N+1 — if 1 parent load causes 50 SQL queries, you have N+1.
Step 3: Run EXPLAIN/EXPLAIN ANALYZE on slow query in DB directly. Look for Seq Scan → add index.
Step 4: Use DTO projections instead of fetching entire entities when you only need 2–3 fields.
Step 5: Check fetch type — is EAGER pulling unnecessary joins?
Step 6: Enable hibernate statistics: hibernate.generate_statistics=true — shows query count per request.
🔑 Key Concepts: Hibernate SQL logging, EXPLAIN ANALYZE, DTO projections, fetch strategies, statistics
S11 How do you write unit tests for a Spring Boot
REST controller without starting the full
server?
@WebMvcTest: Loads only the web layer (Controller, ControllerAdvice, filters). Does NOT load @Service
or @Repository — much faster than @SpringBootTest.
@MockBean: Creates a Mockito mock and registers it as a Spring bean. Use to mock service layer.
MockMvc: Simulates HTTP requests without starting actual server. Test request/response, status codes,
JSON body.
Always test: happy path, validation errors, exception handling (404, 400, 500 responses).
🔑 Key Concepts: @WebMvcTest, @MockBean, MockMvc, unit testing, test slices
S12 A user complains their profile update is
overwriting another user's concurrent update.
What is happening and how do you fix it?
This is a lost update problem — classic race condition on data.
Cause: User A reads profile (v1), User B reads profile (v1), A saves (v2), B saves (v2) — B's save
overwrites A's changes.
Fix with Optimistic Locking: Add @Version field to entity. B's save will throw OptimisticLockException
because version no longer matches.
Client must handle OptimisticLockException: retry with fresh data OR show user 'someone else changed
this record, please review'.
Alternative: Last-Write-Wins with ETag header — client sends ETag, server rejects if ETag doesn't match
current version.
🔑 Key Concepts: @Version, optimistic locking, ETag, lost update problem, retry logic
S13 How do you secure a REST API endpoint so
only authenticated users with specific roles
can access it?
Step 1: Add spring-boot-starter-security + jjwt dependencies.
Step 2: JWT filter: Intercepts every request, extracts Bearer token, validates signature, loads UserDetails
into SecurityContext.
Step 3: SecurityFilterChain: Configure which endpoints are public (/auth/**) and which require auth.
Step 4: Method security (@PreAuthorize): Fine-grained control at method level.
Step 5: Never store sensitive data in JWT payload — it's only Base64 encoded, not encrypted. Use
HTTPS always.
🔑 Key Concepts: Spring Security, JWT, SecurityFilterChain, @PreAuthorize, OncePerRequestFilter
S14 Your microservice needs to call 3 external
APIs and combine results. How do you do it
efficiently?
Sequential calls: total time = t1 + t2 + t3. Bad if services are independent.
Parallel calls with CompletableFuture: total time = max(t1, t2, t3). Best approach.
Use [Link]() to wait for all, [Link]() if only first result needed.
Add timeouts: orTimeout(5, [Link]) to each future — don't let one slow service block all.
Use a dedicated thread pool for I/O-bound calls, not the common ForkJoinPool.
🔑 Key Concepts: CompletableFuture, parallelism, timeout, thread pools, non-blocking I/O
S15 How do you implement caching in Spring
Boot? What can go wrong with caching?
Basic: @EnableCaching + @Cacheable(value="users", key="#id") on service method.
@CachePut: Updates cache on write. @CacheEvict: Removes from cache on delete.
Problems: (1) Stale data — set TTL appropriately. (2) Cache stampede — many requests hit DB
simultaneously when cache expires → use probabilistic early expiry or locking.
(3) Cache inconsistency in clustered env — use distributed cache (Redis) not in-memory (Caffeine) for
multi-instance apps.
(4) Caching mutable objects — if you modify the returned object, you modify the cached version too
(shallow cache). Return copies.
🔑 Key Concepts: @Cacheable, @CacheEvict, Redis, TTL, cache stampede, distributed caching
SECTION 11 — TOP 20 MUST-REVISE QUESTIONS
(Highest ROI)
STRATEGY: These 20 questions appear in over 80% of Java backend interviews. If you can answer ALL
of these with code examples, you will clear most screening rounds.
Q1 HashMap internal working — hashing, collision, Red-Black tree threshold 1-2 YRS
Q2 String Pool — how many objects created, == vs .equals(), intern() FRESH
ER
Q3 equals() & hashCode() contract — why both must be overridden together 1-2 YRS
Q4 Abstract class vs Interface — when to use which with real project example FRESH
ER
Q5 Checked vs Unchecked exceptions — when to use each, override rules FRESH
ER
Q6 synchronized: method vs block, instance vs static, which lock object 1-2 YRS
Q7 wait() vs sleep() — which releases lock, which class they belong to 1-2 YRS
Q8 volatile — what it solves, what it does NOT solve (atomicity) 2-3 YRS
Q9 N+1 query problem — how it happens, 3 ways to fix 1-2 YRS
Q10 @Transactional — default rollback behavior, propagation, self-invocation bug 2-3 YRS
Q11 Lazy vs Eager fetching — pros/cons, when each causes issues 1-2 YRS
Q12 Stream intermediate vs terminal — lazy evaluation explained 1-2 YRS
Q13 Optional — correct vs wrong usage (never call .get() without check) 1-2 YRS
Q14 CompletableFuture — parallel execution, exception handling, timeouts 2-3 YRS
Q15 Spring bean lifecycle — @PostConstruct, @PreDestroy, their real use cases 1-2 YRS
Q16 ConcurrentHashMap — how it differs from Hashtable, Java 8 CAS approach 2-3 YRS
Q17 @ControllerAdvice — write a complete global exception handler with ValidationException 1-2 YRS
Q18 Deadlock — how it happens, consistent lock ordering fix with code 2-3 YRS
Q19 SQL DENSE_RANK() for Nth salary, department-wise top-N employees 1-2 YRS
Q20 Indexing — when index helps vs hurts, why functions on columns kill index usage 1-2 YRS
SECTION 12 — 10 TRICKY QUESTIONS (Where
Candidates Fail)
T1. Can two unequal objects have the same hashCode?
YES — this is a hash collision. hashCode doesn't need to be unique. equals() resolves actual equality.
Confused candidates say 'no' and fail immediately.
T2. Output: String s="Hello"; [Link](" World"); [Link](s);
Output: Hello — NOT 'Hello World'. String is immutable. concat() returns a new object; the result is
discarded because it's not assigned back.
T3. Does a finally block ALWAYS execute?
NO. It does NOT execute if: [Link]() is called, JVM crashes, the thread running the try block is killed,
or an infinite loop occurs in try. Candidates who say 'always' are wrong.
T4. What happens when you call a @Transactional method from the same class?
Transaction is NOT applied — Spring uses a proxy to apply @Transactional, and self-calls bypass the
proxy entirely. This is one of the most common Spring bugs in real projects.
T5. Is a Singleton Spring bean thread-safe?
NO — not automatically. Singleton means ONE instance per context. If that bean has mutable state
(instance variables), multiple threads will race on that state. Stateless beans (no instance vars) are
effectively thread-safe.
T6. volatile int counter++; — is this thread-safe?
NO. volatile ensures visibility (other threads see the latest value) but NOT atomicity. counter++ is 3
operations: read, increment, write. Use AtomicInteger instead.
T7. Can you override a static method in Java?
NO — static methods are class-level, not instance-level. They are HIDDEN, not overridden. @Override on
a static method will not compile. Polymorphism does not apply to static methods.
T8. What is the output: int a=5; int b=10; [Link]("Sum: " + a + b); ?
Output: Sum: 510 — NOT Sum: 15. String concatenation is left-to-right. "Sum: " + a = "Sum: 5" (String),
then + b appends b as String. Fix: "Sum: " + (a + b).
T9. ConcurrentHashMap — can you use it if you need atomic compound operations?
Individual operations are atomic (put, get, remove). But compound operations like if()
[Link](k,v) are NOT atomic. Must use computeIfAbsent() or merge() instead.
T10. Why does [Link]() modify the list but [Link]() does not?
[Link]() sorts IN-PLACE (modifies original list). [Link]() is an intermediate operation that
returns a NEW sorted stream — the original collection is unchanged. Candidates get confused and think
both behave the same.
SECTION 13 — COMMON MISTAKES THAT GET
CANDIDATES REJECTED
MISTAKE WHY IT FAILS IN INTERVIEW
Knows HashMap but not Says 'linked list on collision' but doesn't mention Red-Black tree at 8
collision resolution entries. Stops at Java 7 knowledge. → Rejected at product companies.
Explains volatile but claims it Volatile only solves visibility. Saying 'I made the variable volatile so it's
solves all threading problems thread-safe' without knowing it doesn't fix atomicity is a critical error.
Writes @Transactional without Adds @Transactional everywhere. Doesn't know self-invocation breaks it,
knowing its pitfalls doesn't know it only rolls back on RuntimeException by default, doesn't
know REQUIRES_NEW creates a NEW transaction.
Uses [Link]() without Wraps return in [Link]() but then calls .get() directly. This is worse
checking isPresent() than not using Optional at all — it just moves the NullPointerException to a
NoSuchElementException.
Fetches entire entity when only Writes findAll() and returns List<Employee> to UI when only name and
2 fields needed email are needed. Should use DTO projections. Shows no awareness of
DB performance.
Knows N+1 problem name but Says 'N+1 is when Hibernate fires multiple queries'. Can't write the JOIN
not the fix FETCH or @EntityGraph fix. Knowledge without application = not hired.
Copies code to multiple Writes try-catch in every controller method. Shows no knowledge of Spring
controllers instead of using exception handling best practices.
@ControllerAdvice
Uses parallelStream() Adds parallelStream() thinking it always speeds up code. Doesn't know
everywhere for performance about ForkJoinPool sharing, thread-safety issues, or that parallel has
overhead for small collections.
Doesn't know how indexes hurt Says 'I add indexes to make queries faster' without knowing that every
write performance INSERT/UPDATE/DELETE must update all indexes on that table. Indexes
have real cost.
Explains Microservices benefits, Lists 5 benefits of microservices without knowing that debugging across
ignores downsides services is harder, distributed transactions are painful, and operational
complexity is massive. Sounds like they read a blog post, not worked on
production.
PREPARATION STRATEGY
Week 1: Core Java (Sections 1–3). Revise Top 20 list.
Week 2: Multithreading (Section 4) + Spring Boot (Sections 5–6).
Week 3: JPA (Section 7) + SQL (Section 8). Write every query by hand.
Week 4: All 15 Scenarios (Section 10). Practise explaining out loud.
Daily: Solve 2 LeetCode Easy/Medium SQL + 1 Java coding problem.