162 Java Interview Questions and Answers (2026)

Blog / 162 Java Interview Questions and Answers (2026)
Java interview questions and answers

Java still runs the enterprise, banking, commerce, Android, and the high-scale backends behind services you use daily. Demand for strong Java engineers stays high, and interviewers expect genuine fluency, not memorized buzzwords. Walk in shaky on Collections, concurrency, or the memory model and you will lose the offer to someone who is not.

This guide gives you 162 questions with concise, interview-ready answers and code where it actually helps. They're worked Junior → Mid → Senior, so you build from fundamentals up to virtual threads, GC internals, and the JVM. Work through them and you'll walk in ready to explain anything they throw at you.

Q1.
Explain the difference between 'Comparable' and 'Comparator'. When is each appropriate?

Junior

Comparable defines a type's single natural ordering via compareTo() inside the class itself, while Comparator is an external, reusable object defining alternative orderings via compare().

  • Comparable:

    • Implemented by the class being sorted; one compareTo(T o) method in java.lang.

    • Defines the natural order used by Collections.sort(), TreeMap, TreeSet by default (e.g. String alphabetical, Integer numeric).

  • Comparator:

    • A separate object with compare(T a, T b) in java.util; you can define many for one type.

    • Ideal when you can't modify the class, need multiple orderings, or want to sort by different fields.

    • Composes fluently: Comparator.comparing(...).thenComparing(...).reversed().

  • Rule of thumb: one obvious intrinsic order, use Comparable; multiple or external orderings, use Comparator.

java

// Natural order class Person implements Comparable<Person> { int age; public int compareTo(Person o) { return Integer.compare(age, o.age); } } // External orderings Comparator<Person> byName = Comparator.comparing(p -> p.name); list.sort(byName.thenComparing(p -> p.age).reversed());

Q2.
What is the time complexity of searching in an ArrayList vs. a LinkedList? Why?

Junior

Unsorted search is O(n) for both because you must scan elements, but ArrayList beats LinkedList in practice and offers O(1) indexed access while LinkedList has none.

  • Search by value: both O(n): Worst case scans every element via contains()/indexOf().

  • Access by index differs:

    • ArrayList.get(i) is O(1): backing array allows direct offset.

    • LinkedList.get(i) is O(n): must walk nodes from the nearest end.

  • Cache locality wins for ArrayList: Contiguous memory means the CPU prefetches sequential elements; linked nodes are scattered, causing cache misses even though both are O(n).

Q3.
What is the difference between HashMap and Hashtable?

Junior

Both implement Map, but HashMap is the modern, non-synchronized choice that allows nulls, while Hashtable is a legacy, synchronized class that forbids nulls.

  • Synchronization:

    • Hashtable synchronizes every method, so it is thread-safe but slow under contention.

    • HashMap is unsynchronized; for concurrency use ConcurrentHashMap instead.

  • Null handling:

    • HashMap allows one null key and many null values.

    • Hashtable throws NullPointerException on any null key or value.

  • Legacy vs modern:

    • Hashtable predates the Collections Framework (Java 1.0); HashMap arrived in 1.2.

    • Hashtable's Enumeration is not fail-fast, while HashMap's iterator is fail-fast.

  • Takeaway: prefer HashMap generally, and ConcurrentHashMap when you need thread safety.

Q4.
What is the difference between Iterator, ListIterator, and the Iterable interface?

Junior

Iterable is the contract for "something you can loop over," while Iterator is the cursor that walks it; ListIterator is a more powerful, bidirectional iterator specific to lists.

  • Iterable: Defines a single method iterator(); implementing it enables the enhanced for-each loop.

  • Iterator:

    • Forward-only: hasNext(), next(), and optional remove().

    • The only safe way to remove during iteration without a ConcurrentModificationException.

  • ListIterator:

    • Extends Iterator, available only on List.

    • Adds bidirectional traversal (hasPrevious(), previous()) plus add() and set() to modify elements in place.

Q5.
Explain the 'Try-with-Resources' statement. What interface must a class implement to be used within it?

Junior

Try-with-resources is a construct that automatically closes resources at the end of a block, eliminating manual finally cleanup. Any resource declared in the parentheses must implement AutoCloseable (or its subtype Closeable).

  • Required interface:

    • The class must implement java.lang.AutoCloseable, whose single method is close().

    • Closeable extends it but its close() only throws IOException.

  • How it works:

    • Resources close in reverse order of declaration, even if an exception is thrown.

    • If the body and close() both throw, the close() exception is added as a suppressed exception (retrievable via getSuppressed()).

  • Since Java 9 you may use an effectively final variable declared earlier, not just a fresh declaration inside the parentheses.

java

try (var in = new FileInputStream("a.txt"); var out = new FileOutputStream("b.txt")) { in.transferTo(out); } // out.close() then in.close() called automatically

Q6.
What are the key methods defined on the Object class, and why are toString(), equals(), and hashCode() so important?

Junior

Every class extends Object, which provides a small set of universally available methods. Three of them, toString(), equals(), and hashCode(), matter most because collections and debugging rely on them.

  • Key Object methods: toString(), equals(), hashCode(), getClass(), clone(), finalize() (deprecated), and the concurrency primitives wait(), notify(), notifyAll().

  • Why the three are critical:

    • toString(): readable representation for logging and debugging; the default is an unhelpful class name plus hash.

    • equals(): defines logical equality; needed for correct lookups, contains, and de-duplication.

    • hashCode(): determines bucket placement in hash-based collections like HashMap and HashSet.

  • The contract: If two objects are equals(), they must have the same hashCode(); violating this breaks hash collections (entries become unfindable). Always override the two together.

Q7.
What is the 'String Pool' and how does it help with memory management?

Junior

The String Pool (string intern pool) is a special area where the JVM stores unique String literal instances so identical literals share one object instead of duplicating in memory.

  • How it works:

    • A string literal like "hello" is interned: the JVM checks the pool and reuses the existing instance if present.

    • Since Java 7 the pool lives in the heap (not PermGen), so it is garbage collected.

  • Memory benefit:

    • Many duplicate literals point to one object, saving memory in literal-heavy code.

    • Enables fast == reference comparison for interned strings.

  • Caveats:

    • new String("x") creates a distinct heap object outside the pool; call .intern() to force pooling.

    • Pooling is only safe because Strings are immutable; a shared mutable string would be disastrous.

Q8.
What is the difference between String, StringBuilder, and StringBuffer, and when would you use each?

Junior

All three handle text, but String is immutable, StringBuilder is a mutable, fast, non-thread-safe builder, and StringBuffer is its synchronized (thread-safe) counterpart.

  • String:

    • Immutable: every concatenation creates a new object, so repeated modification in a loop is wasteful.

    • Use for fixed or rarely-changed text and as map keys.

  • StringBuilder:

    • Mutable, not synchronized, so it's the fastest choice for building strings within a single thread.

    • Default choice for loops and heavy concatenation.

  • StringBuffer:

    • Same API as StringBuilder but methods are synchronized; slower due to locking.

    • Use only when one buffer is genuinely shared across threads (rare).

java

// Prefer StringBuilder for loops StringBuilder sb = new StringBuilder(); for (int i = 0; i < n; i++) sb.append(i); String result = sb.toString();

Q9.
Explain the contract between 'equals()' and 'hashCode()'. What happens if you break it?

Junior

The contract says equal objects must have equal hash codes; if you break it, hash-based collections (HashMap, HashSet) behave incorrectly: lookups fail and duplicates appear.

  • The rules:

    1. If a.equals(b) is true, then a.hashCode() == b.hashCode() must be true.

    2. Equal hash codes do NOT require equality (collisions are allowed).

    3. Both must stay consistent across multiple calls (given the object isn't mutated).

  • What breaks if you violate it:

    • Equal objects with different hash codes land in different buckets, so get() or contains() can't find them.

    • You can store "duplicate" logically-equal keys in a HashSet.

  • Mutability caveat: Mutating a field used in hashCode() after insertion strands the object in the wrong bucket.

Q10.
What is the contract between hashCode() and equals(), and what happens if you override one but not the other?

Junior

The contract requires that equal objects produce equal hash codes; overriding only one of the pair breaks hash-based collections, because they use both methods together to locate objects.

  • Override equals() but NOT hashCode():

    • The default hashCode() (identity-based) gives two logically-equal objects different hash codes.

    • They map to different buckets, so a HashMap lookup with an equal-but-different instance fails.

  • Override hashCode() but NOT equals(): Default equals() compares references, so logically-equal objects are never considered equal: duplicates accumulate.

  • Practical rule: Always override both together, using the same fields. Objects.equals() and Objects.hash() make this easy.

java

@Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Point p)) return false; return x == p.x && y == p.y; } @Override public int hashCode() { return Objects.hash(x, y); }

Q11.
Why is it critical to override hashCode() whenever you override equals()? What happens in a HashSet if you don't?

Junior

Because hash collections locate elements by hash code first, then confirm with equals(); if you override only equals(), equal objects get different hash codes and end up in different buckets, defeating the comparison entirely.

  • How a HashSet works:

    1. Compute the element's hashCode() to pick a bucket.

    2. Within that bucket, use equals() to check for an existing match.

  • If you don't override hashCode():

    • Two logically-equal objects get the default identity hash codes (almost always different).

    • They go to different buckets, so the equals() check never runs against each other.

    • Result: add() stores both, contains() returns false for an equal instance: the set holds "duplicates".

Q12.
Is Java 'Pass-by-Value' or 'Pass-by-Reference'? Explain with an example of an Object.

Junior

Java is strictly pass-by-value. For objects, the value passed is a copy of the reference (the pointer), not the object itself, so the method can mutate the shared object but cannot make the caller's variable point somewhere else.

  • Primitives pass a copy of the value: Reassigning the parameter inside the method has no effect on the caller.

  • Objects pass a copy of the reference:

    • Both copies point to the same object, so calling a mutator (e.g. a setter) is visible to the caller.

    • Reassigning the parameter (obj = new ...) only rebinds the local copy, leaving the caller untouched.

  • This is why it is not pass-by-reference: true pass-by-reference would let the method swap the caller's variable.

java

void mutate(StringBuilder sb) { sb.append(" world"); // visible to caller (same object) sb = new StringBuilder("new"); // only rebinds local copy } StringBuilder s = new StringBuilder("hello"); mutate(s); System.out.println(s); // "hello world"

Q13.
Is Java pass-by-value or pass-by-reference? Explain what happens when you pass an object reference to a method.

Junior

Java is always pass-by-value. When you pass an object, you pass a copy of the reference value, so the method shares the same object but holds its own independent variable pointing at it.

  • What gets copied: The reference (an address-like value) is copied into the parameter, not the object's contents.

  • Mutating through the reference works: Calls like list.add(x) affect the one shared object and are seen by the caller.

  • Reassigning the parameter does not: Setting the parameter to a new object changes only the local copy; the caller still sees the original.

  • Mental model: you copy the remote control, not the TV. You can change the channel, but you cannot make the caller's remote point at a different TV.

Q14.
What is the difference between method overloading and method overriding, and how does static (compile-time) versus dynamic (runtime) binding apply to each?

Junior

Overloading is multiple methods with the same name but different parameter lists in the same class, resolved at compile time (static binding); overriding is a subclass redefining an inherited method with the same signature, resolved at runtime (dynamic binding) based on the actual object type.

  • Method overloading (compile-time):

    • Same name, different parameters (count, types, or order); return type alone is not enough.

    • The compiler picks the target from the declared/static types of the arguments: static binding.

  • Method overriding (runtime):

    • Same signature in a subclass; use @Override to catch mistakes.

    • The JVM dispatches to the actual object's implementation via the virtual method table: dynamic binding.

  • Binding summary: Static binding also applies to static, private, and final methods, which cannot be polymorphically overridden.

java

Animal a = new Dog(); a.sound(); // overriding: runs Dog.sound() (runtime type) void print(int x) {} // overloading void print(String x) {} // chosen at compile time by arg type

Q15.
What is the difference between '==' and the 'equals()' method when comparing objects in Java?

Junior

== compares references (whether two variables point to the same object), while equals() compares logical/value equality as defined by the class.

  • == is identity (or value for primitives): For objects it is true only if both refer to the exact same instance on the heap.

  • equals() is logical equality: The default Object.equals() just does ==; classes like String override it to compare contents.

  • Contract: override hashCode() too: Equal objects must return equal hash codes, or hash-based collections (HashMap, HashSet) misbehave.

  • Null-safety tip: use Objects.equals(a, b) or call equals on a known non-null constant.

java

String a = new String("hi"); String b = new String("hi"); a == b; // false (different objects) a.equals(b); // true (same contents)

Q16.
What does the 'static' keyword mean, and how do static initializer blocks and static fields get initialized when a class is loaded?

Junior

static means a member belongs to the class itself rather than to any instance, so it is shared across all objects and accessed via the class name. Static fields and static initializer blocks run once, during class initialization, in the textual order they appear.

  • What static applies to: Fields (one shared copy), methods (no this, cannot be overridden polymorphically), nested classes, and initializer blocks.

  • When initialization happens: On first active use of the class (first instance, first static access, or subclass init): lazy and thread-safe by the JVM.

  • Order of static initialization:

    • Static fields get default values, then static field initializers and static { } blocks run top to bottom.

    • Useful for setting up complex static state or constants computed at load time.

  • Pitfall: static members are not garbage-collected with instances and can leak memory or cause hidden shared-state bugs.

java

class Config { static int x = 10; static int y; static { // runs once at class init y = x * 2; } }

Q17.
What are the four access modifiers in Java (public, protected, default, private) and what visibility does each provide?

Junior

Java has four access levels controlling where a member is visible, from most open to most restricted: public, protected, default (package-private), and private.

  • public: Visible everywhere, from any class in any package.

  • protected: Visible within the same package and to subclasses (even in other packages, through inheritance).

  • default (no keyword, package-private): Visible only within the same package; this is what you get when you omit a modifier.

  • private: Visible only within the same class (the enclosing top-level class, including its nested classes).

  • Note: top-level classes can only be public or package-private; the other two apply to members and nested types. Favor the most restrictive level that works (encapsulation).

Q18.
What are varargs, and what are the rules and pitfalls when using them?

Junior

Varargs (Type... name) let a method accept a variable number of arguments, which the compiler packages into an array. They make APIs flexible but carry resolution and safety pitfalls.

  • How they work:

    • Inside the method the parameter is a real array, so you iterate it normally.

    • Callers can pass zero or more values, or pass an array directly.

  • Rules: A varargs parameter must be the last parameter, and a method can have only one.

  • Pitfalls:

    • Ambiguity: fixed-arity overloads are preferred over varargs, which can surprise overload resolution.

    • Passing null or a single array is ambiguous (is it the array, or one element?); cast to clarify.

    • Generic varargs cause unchecked/heap-pollution warnings; annotate trusted methods with @SafeVarargs.

    • Minor cost: an array is allocated per call.

java

int sum(int... nums) { // nums is an int[] int total = 0; for (int n : nums) total += n; return total; } sum(); // 0 args -> empty array sum(1, 2, 3); // 3 args sum(new int[]{1,2}); // array passed directly

Q19.
What is a Functional Interface? Can you name three built-in ones in the JDK?

Junior

A functional interface is an interface with exactly one abstract method (SAM: Single Abstract Method), which makes it a valid target for a lambda expression or method reference.

  • One abstract method:

    • It may still have default and static methods; those don't count against the single-abstract-method rule.

    • Annotate with @FunctionalInterface to have the compiler enforce the contract (optional but recommended).

  • Three built-in examples:

    1. Predicate<T>: boolean test(T t) for filtering.

    2. Function<T,R>: R apply(T t) for transforming a value.

    3. Supplier<T>: T get() for lazily producing a value (others: Consumer<T>, Runnable).

java

@FunctionalInterface interface Validator { boolean isValid(String s); } Validator notEmpty = s -> !s.isBlank(); // lambda targets the SAM

Q20.
Explain the difference between 'Intermediate' and 'Terminal' operations in the Stream API.

Junior

Intermediate operations transform a stream and return another stream, so they can be chained; terminal operations consume the stream and produce a result (or side effect), ending the pipeline.

  • Intermediate operations:

    • Return a Stream, e.g. filter(), map(), sorted(), distinct().

    • Lazy: they don't execute until a terminal operation runs.

  • Terminal operations:

    • Produce a non-stream result, e.g. collect(), forEach(), reduce(), count().

    • Trigger execution of the whole pipeline and consume the stream.

  • A stream can be used only once: after a terminal operation it is consumed, and reusing it throws IllegalStateException.

Q21.
What is the purpose of 'Optional'? Does it prevent NullPointerExceptions entirely?

Junior

Optional<T> is a container that may or may not hold a value, used to model 'a result might be absent' explicitly in the type signature. It reduces NPEs by forcing callers to handle absence, but it does not eliminate them entirely.

  • Makes absence explicit: A method returning Optional<User> signals callers must consider the empty case, instead of silently returning null.

  • Encourages safe handling: Use orElse(), orElseGet(), map(), ifPresent() rather than checking for null.

  • It does NOT prevent all NPEs:

    • Calling get() on an empty Optional throws NoSuchElementException.

    • An Optional reference itself can be null if you assign null to it (an anti-pattern).

  • Intended use: as a return type. Avoid using it for fields, parameters, or in collections.

Q22.
What is a 'Method Reference' and how does it relate to Lambda expressions?

Junior

A method reference is shorthand for a lambda that does nothing but call an existing method; ClassName::method is more readable than x -> ClassName.method(x). Both are compiled to the same functional-interface target.

  • It's syntactic sugar over a lambda:

    • s -> s.toUpperCase() becomes String::toUpperCase.

    • Use it only when the lambda just forwards its arguments to one method.

  • Four forms:

    1. Static: Integer::parseInt.

    2. Instance of a particular object: System.out::println.

    3. Instance of an arbitrary object of a type: String::toUpperCase.

    4. Constructor: ArrayList::new.

Q23.
What makes an interface a 'Functional Interface', and can you have multiple methods in it if they are default or static?

Junior

An interface is a functional interface when it has exactly one abstract method (the SAM, single abstract method), which lets it be the target of a lambda or method reference. It can still hold any number of default and static methods.

  • Exactly one abstract method: That single method defines the lambda's shape; @FunctionalInterface makes the compiler enforce this (optional but recommended).

  • default and static methods don't count: They have bodies, so they aren't abstract; you can have many of them and the interface stays functional.

  • public methods of Object don't count either: Re-declared methods like equals or toString are ignored when counting abstract methods (e.g. Comparator).

java

@FunctionalInterface interface Calculator { int apply(int a, int b); // the one abstract method default int twice(int a) { return apply(a, a); } // allowed static Calculator add() { return (a, b) -> a + b; } // allowed }

Q24.
What makes an interface a 'Functional Interface'? Can a functional interface have multiple methods such as default or static methods?

Junior

An interface is functional when it declares exactly one abstract method, making it a valid target for a lambda or method reference. Yes, it may also contain any number of default and static methods, because those have implementations and aren't abstract.

  • The single-abstract-method rule: Exactly one abstract method defines the lambda signature; annotate with @FunctionalInterface to have the compiler verify it.

  • default methods: Provide reusable behavior on the interface (e.g. Function.andThen); you can have many without breaking functional status.

  • static methods: Factory/utility helpers tied to the interface (e.g. Function.identity); also unlimited.

  • Object methods are excluded: Abstract redeclarations of equals, hashCode, toString don't count toward the one-method limit.

  • Built-in examples: Runnable, Comparator, Function, Predicate, Supplier.

Q25.
Explain the different states of a Java thread and what causes a thread to move from Runnable to Waiting.

Junior

A Java thread has six states defined in Thread.State: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, and TERMINATED. A thread leaves RUNNABLE for WAITING when it voluntarily waits indefinitely for another thread to act.

  • The states:

    • NEW: created but start() not yet called.

    • RUNNABLE: eligible to run (running or waiting for CPU); the JVM does not distinguish 'ready' from 'running'.

    • BLOCKED: waiting to acquire a monitor lock to enter a synchronized region.

    • WAITING: waiting indefinitely until another thread signals it.

    • TIMED_WAITING: same but with a timeout.

    • TERMINATED: finished execution.

  • What moves RUNNABLE to WAITING:

    • Calling Object.wait() (with no timeout), Thread.join(), or LockSupport.park().

    • The thread returns to RUNNABLE via notify()/notifyAll(), the joined thread ending, or unpark().

  • BLOCKED vs WAITING: BLOCKED is contention for a lock; WAITING is a voluntary pause awaiting a condition.

Q26.
What is the difference between the Stack and the Heap? What specifically is stored in each?

Junior

The stack holds per-thread method execution data (frames with local variables and references), while the heap is the shared region where all objects and their instance data live. Each thread has its own stack; the heap is shared across all threads.

  • The stack:

    • Stores a frame per method call: primitives declared locally, and references (not the objects themselves) to heap data.

    • LIFO and automatically freed when a method returns; overflow throws StackOverflowError.

    • Thread-confined, so its data is inherently not shared.

  • The heap:

    • Stores every object created with new, arrays, and their instance fields.

    • Managed by the garbage collector; exhaustion throws OutOfMemoryError.

    • Shared, so concurrent access needs synchronization.

  • Key consequence: A local reference variable lives on the stack but points to an object on the heap, which is why an object outlives the method that created it if still referenced.

Q27.
What is the difference between the JDK, the JRE, and the JVM?

Junior

The JVM runs bytecode, the JRE bundles the JVM plus the libraries needed to run apps, and the JDK adds the tools needed to develop and compile them. They nest: JDK ⊃ JRE ⊃ JVM.

  • JVM (Java Virtual Machine):

    • An abstract runtime that loads .class bytecode, verifies it, and executes it (interpreting plus JIT compilation).

    • Provides platform independence: same bytecode, many OS-specific JVM implementations.

  • JRE (Java Runtime Environment): JVM + core class libraries (java.lang, collections, etc.) needed to run a Java program but not compile one.

  • JDK (Java Development Kit):

    • JRE + developer tools: javac (compiler), jar, javadoc, jdb.

    • What you install to build software; note since Java 11 there is no standalone public JRE download.

Q28.
Explain the 'final', 'finally', and 'finalize' keywords. Why is 'finalize' deprecated?

Junior

They are unrelated despite the similar names: final is a modifier that prevents change, finally is a block that always runs after a try, and finalize() was a method the garbage collector called before reclaiming an object. finalize() is deprecated because it is unreliable and dangerous.

  • final (modifier):

    • On a variable: assign once (constant/reference can't be reseated).

    • On a method: can't be overridden; on a class: can't be subclassed.

  • finally (block):

    • Runs whether or not an exception is thrown, for cleanup (closing resources).

    • Often replaced by try-with-resources for AutoCloseable objects.

  • finalize() (method, deprecated):

    • Intended for last-chance cleanup before GC, but there is no guarantee it runs, when it runs, or that it runs at all.

    • It can resurrect objects, hurt GC performance, and hide exceptions: hence deprecated since Java 9.

    • Use try-with-resources or java.lang.ref.Cleaner instead.

Q29.
What is the difference between a fail-fast and a fail-safe iterator, and which collections use which and why?

Mid

A fail-fast iterator throws ConcurrentModificationException the moment it detects the collection was structurally modified during iteration; a fail-safe iterator works on a snapshot or tolerates concurrent changes and never throws.

  • Fail-fast:

    • Detects changes via a modCount counter compared against an expected value; a mismatch triggers ConcurrentModificationException.

    • Used by most java.util collections: ArrayList, HashMap, HashSet.

    • Best-effort only: it is a debugging aid, not a guarantee, so don't build logic on it.

  • Fail-safe:

    • Iterates over a copy/snapshot or uses weakly-consistent traversal, so structural changes don't disturb it.

    • Used by concurrent collections: CopyOnWriteArrayList (snapshot) and ConcurrentHashMap (weakly consistent).

    • Trade-off: may not reflect the latest writes and can cost extra memory.

  • Why the split: single-threaded collections favor early failure to catch bugs; concurrent collections must stay usable under simultaneous reads and writes.

Q30.
What are Sequenced Collections, and what problem do they solve in the existing Collections hierarchy?

Mid

Sequenced Collections (JDK 21, JEP 431) are a set of interfaces that give a uniform, well-defined encounter order with first/last access and reversal to collections that always had an order but no common API for it.

  • The problem they solve: Ordered types like List, LinkedHashSet, and Deque had inconsistent ways to get the first/last element or iterate in reverse (list.get(0) vs deque.getFirst() vs awkward iterators for sets).

  • New interfaces:

    • SequencedCollection: adds getFirst(), getLast(), addFirst(), addLast(), and reversed().

    • SequencedSet and SequencedMap (with firstEntry(), lastEntry(), reversed()).

  • reversed() returns a view over the same data, not a copy, so changes write through.

Q31.
Why does ConcurrentHashMap not allow null keys or values, while HashMap does?

Mid

ConcurrentHashMap forbids null keys and values because in a concurrent setting a null return from get() would be ambiguous: you couldn't tell "key absent" from "key mapped to null," and there's no safe atomic way to disambiguate without locking.

  • The ambiguity problem:

    • In HashMap you can follow get()==null with containsKey() to disambiguate.

    • In a concurrent map another thread could insert or remove between those two calls, making the check unreliable.

  • HashMap is single-threaded by design: No concurrency means the get() + containsKey() pattern is safe, so one null key and null values are permitted.

  • Doug Lea's rationale: nulls are an open door to errors in concurrent code, so the API rejects them outright (throws NullPointerException).

Q32.
What is the difference between 'fail-fast' and 'fail-safe' (non-blocking) iterators?

Mid

Fail-fast iterators throw ConcurrentModificationException when the underlying collection is structurally modified during iteration, while fail-safe (weakly-consistent / non-blocking) iterators iterate without throwing by working over a snapshot or tolerating concurrent changes.

  • Mechanism:

    • Fail-fast tracks a modCount; each next() checks it matches the expected count and throws on mismatch.

    • Fail-safe iterates over a copy (CopyOnWriteArrayList) or uses a weakly-consistent view (ConcurrentHashMap) that never throws.

  • Visibility: Fail-safe traversal may miss updates made after the iterator was created and won't reflect concurrent writes.

  • Practical note: Even single-threaded code triggers fail-fast if you modify a collection directly (not via Iterator.remove()) inside a loop.

Q33.
When would you use a CopyOnWriteArrayList over a synchronized List?

Mid

Use CopyOnWriteArrayList when reads vastly outnumber writes and you want lock-free, never-throwing iteration; use a synchronized List when writes are frequent or the list is large, since every mutation copies the whole array.

  • How CopyOnWriteArrayList works:

    • Every write (add, set, remove) copies the entire backing array under a lock.

    • Reads and iteration are lock-free and operate on an immutable snapshot, so iterators never throw ConcurrentModificationException.

  • When to prefer it:

    • Read-mostly data: listener lists, configuration, caches that rarely change.

    • You iterate often and want a stable view without external locking.

  • When NOT to use it:

    • Write-heavy or large lists: O(n) copy per write kills performance and memory.

    • A Collections.synchronizedList serializes all access but avoids copying, and needs manual synchronization during iteration.

Q34.
What problem do Sequenced Collections (introduced in Java 21) solve that the previous Collections hierarchy did not?

Mid

Before Java 21 there was no common interface expressing a defined encounter order with first/last access, so working with the ends of ordered collections was inconsistent and verbose. SequencedCollection (and friends) unify that.

  • The old inconsistency: List had get(0) and get(size()-1); Deque had getFirst()/getLast(); LinkedHashSet had ordering but no clean way to get the last element.

  • The unified API: getFirst(), getLast(), addFirst(), addLast(), removeFirst(), removeLast(), and reversed().

  • New interfaces: SequencedCollection, SequencedSet, SequencedMap retrofit existing types like List, Deque, LinkedHashSet, and LinkedHashMap.

Q35.
How does a HashMap handle collisions internally in Java 8+, including the transition from Linked List to Balanced Tree?

Mid

A HashMap places entries in buckets by hash; when multiple keys land in the same bucket it chains them, starting as a linked list and converting to a balanced (red-black) tree once a bucket gets large, to cap worst-case lookup.

  • Bucket selection: Key's hashCode() is spread (high bits XORed in) then masked to an index; entries with the same index collide.

  • Linked list phase: Colliding entries form a singly linked list in the bucket; lookup is O(n) within that bucket.

  • Treeification:

    • When a bucket reaches TREEIFY_THRESHOLD (8) AND table size is at least MIN_TREEIFY_CAPACITY (64), the list becomes a red-black tree, giving O(log n) in that bucket.

    • Below capacity 64 it resizes instead of treeifying.

  • Untreeify: If removals shrink a tree bucket to UNTREEIFY_THRESHOLD (6), it reverts to a linked list.

  • Why it matters: It bounds worst-case from O(n) to O(log n), mitigating hash-collision DoS attacks (requires keys to be Comparable for ordering).

Q36.
What is the difference between List.of() and Arrays.asList() regarding mutability and null handling?

Mid

List.of() creates a truly immutable list that rejects null, while Arrays.asList() returns a fixed-size, partially mutable view backed by an array that does allow null.

  • Mutability:

    • List.of(): fully immutable; any add(), set(), or remove() throws UnsupportedOperationException.

    • Arrays.asList(): fixed size, but set() works and writes through to the backing array; add()/remove() throw.

  • Null handling:

    • List.of() throws NullPointerException if any element is null.

    • Arrays.asList() permits null elements.

  • Backing: Arrays.asList(arr) stays linked to the array: external array changes are visible in the list and vice versa.

Q37.
Explain the 'Fail-Fast' vs. 'Fail-Safe' iterator contract. Which collections use which?

Mid

A fail-fast iterator throws ConcurrentModificationException if the collection is structurally modified during iteration, while a fail-safe iterator works on a snapshot or tolerates concurrent change and never throws.

  • Fail-fast:

    • Uses a modCount counter; if it changes unexpectedly, the iterator throws ConcurrentModificationException.

    • Used by ArrayList, HashMap, HashSet, LinkedList (the standard non-concurrent collections).

    • Best-effort only: detection is not guaranteed, so don't rely on it for correctness.

  • Fail-safe (weakly consistent):

    • Iterates over a copy or a stable snapshot, so concurrent modification is allowed without exceptions.

    • Used by ConcurrentHashMap, CopyOnWriteArrayList, and other java.util.concurrent collections.

    • Trade-off: may not reflect the latest state and (for copy-on-write) costs extra memory.

Q38.
What gap in the Collections Framework did Java 21's SequencedCollection interface fill, and how does it unify the behavior of LinkedHashSet and ArrayList?

Mid

The framework had ordered collections but no shared abstraction for their order, so the same first/last operations had different names (or were missing) across types; SequencedCollection fills that gap with one consistent contract.

  • The gap: No common type guaranteed a defined encounter order plus symmetric access/insertion/removal at both ends and a reversed view.

  • How it unifies:

    • Both ArrayList and LinkedHashSet now implement SequencedCollection, so both expose getFirst(), getLast(), addFirst(), addLast(), and reversed().

    • Before, LinkedHashSet forced you to iterate to reach its last element; now it is a single getLast() call.

  • reversed() is a view: It returns a live, backed view rather than a copy, so it stays in sync with the underlying collection.

Q39.
How do TreeMap and TreeSet maintain ordering, and what is their time complexity for basic operations?

Mid

Both are backed by a self-balancing Red-Black tree that keeps elements sorted by natural ordering or a supplied Comparator, giving guaranteed O(log n) for the core operations.

  • How ordering is maintained:

    • Each insert/delete rebalances the Red-Black tree (rotations + recoloring) to keep it roughly height-balanced.

    • Ordering comes from Comparable.compareTo() or the Comparator passed to the constructor, not from hashCode().

  • Time complexity:

    • get, put, remove, contains: O(log n) (vs amortized O(1) for HashMap/HashSet).

    • Navigation queries like first(), floor(), ceiling(), subMap() are also O(log n).

  • Relationship: TreeSet is internally backed by a TreeMap, and both implement NavigableMap/NavigableSet.

  • Consistency caveat: the comparator must be consistent with equals, or the structure behaves inconsistently with the Set contract.

Q40.
What is a BlockingQueue, and how does it support the producer-consumer pattern?

Mid

A BlockingQueue is a thread-safe queue whose operations can block: a consumer waits when it's empty and a producer waits when it's full, which makes the producer-consumer hand-off automatic without manual locking.

  • Blocking operations:

    • put(e) blocks the producer until space is available.

    • take() blocks the consumer until an element exists.

    • Non-blocking/timeout variants (offer(), poll()) exist too.

  • Why it fits producer-consumer:

    • The queue itself handles synchronization and back-pressure, so threads never busy-wait or share locks directly.

    • A bounded capacity throttles fast producers so they don't overwhelm slow consumers.

  • Common implementations: ArrayBlockingQueue (bounded), LinkedBlockingQueue (optionally bounded), PriorityBlockingQueue, and SynchronousQueue (zero capacity, direct hand-off).

java

BlockingQueue<Task> queue = new ArrayBlockingQueue<>(100); // Producer queue.put(task); // waits if full // Consumer Task t = queue.take(); // waits if empty

Q41.
What is the difference between an immutable List created with List.of() and an unmodifiable view created with Collections.unmodifiableList()?

Mid

List.of() creates a genuinely immutable list with its own data, whereas Collections.unmodifiableList() returns a read-only wrapper around an existing list that can still change underneath you.

  • List.of() (truly immutable):

    • Owns its elements; nothing can modify the contents after creation.

    • Rejects null elements and throws UnsupportedOperationException on any mutation.

  • Collections.unmodifiableList() (unmodifiable view):

    • A wrapper: you cannot mutate through the wrapper, but changes to the backing list are still visible through it.

    • So it is read-only, not immutable.

  • Practical rule: use List.of() for true constants/defensive copies; use the wrapper only to hand out a read-only view of a list you still control.

java

List<String> backing = new ArrayList<>(List.of("a", "b")); List<String> view = Collections.unmodifiableList(backing); backing.add("c"); // view now also shows "c"! // view.add("d"); // UnsupportedOperationException List<String> immut = List.of("x", "y"); // fully fixed

Q42.
What is the difference between Checked and Unchecked Exceptions? Why is there a trend toward Unchecked?

Mid

Checked exceptions must be declared or caught at compile time (the compiler enforces handling), while unchecked exceptions (subclasses of RuntimeException) need no declaration; the trend toward unchecked is driven by cleaner code and better fit with functional/stream APIs.

  • Checked exceptions:

    • Extend Exception (but not RuntimeException); compiler forces try/catch or throws.

    • Examples: IOException, SQLException.

  • Unchecked exceptions:

    • Extend RuntimeException; no compiler enforcement.

    • Examples: NullPointerException, IllegalArgumentException.

  • Why the trend toward unchecked:

    • Checked exceptions encourage swallow-and-ignore boilerplate catch blocks.

    • They leak through APIs and break encapsulation as code evolves.

    • Lambdas and Stream functional interfaces don't declare checked exceptions, so they force ugly wrapping.

    • Many modern frameworks (e.g. Spring) wrap checked exceptions like SQLException into unchecked ones.

Q43.
How does 'try-with-resources' work internally? What interface must the resource implement?

Mid

try-with-resources automatically closes resources at the end of the block by having the compiler generate a finally that calls close(); any resource declared must implement AutoCloseable.

  • The required interface: AutoCloseable (one method, close()); Closeable extends it for I/O.

  • What the compiler generates:

    • A hidden finally block calls close() on each resource, in reverse order of declaration.

    • close() is called whether the block exits normally or via exception.

  • Suppressed exceptions: If the body throws and close() also throws, the body's exception propagates and the close() exception is attached via addSuppressed() (retrievable with getSuppressed()).

java

try (BufferedReader br = new BufferedReader(new FileReader("f.txt"))) { return br.readLine(); } // br.close() runs automatically, even on exception

Q44.
What is the philosophical difference between a Checked and an Unchecked exception, and when should you create a custom Checked exception?

Mid

Philosophically, a checked exception models a recoverable condition the caller is expected to anticipate and handle, while an unchecked exception models a programming error or unrecoverable state; create a custom checked exception only when callers can realistically take corrective action.

  • Checked = expected, recoverable:

    • A reasonable caller can do something about it (retry, prompt user, fall back).

    • Example: FileNotFoundException lets the caller ask for a different file.

  • Unchecked = bug or unrecoverable:

    • Indicates broken contracts (null arg, bad index) the caller usually can't sensibly recover from.

    • Forcing handling would just clutter code.

  • When to create a custom checked exception:

    • The failure is part of the expected business flow (e.g. InsufficientFundsException) and the caller must consciously handle it.

    • You want the compiler to guarantee callers acknowledge the outcome.

    • Otherwise prefer an unchecked custom exception to avoid polluting signatures, especially across layered/functional code.

Q45.
Why does Java distinguish between Checked and Unchecked exceptions? What is the modern architectural trend regarding this distinction?

Mid

Java splits exceptions to force a design decision: checked exceptions represent recoverable conditions the caller is expected to anticipate (and the compiler enforces handling), while unchecked exceptions represent programming errors or unrecoverable failures. The modern trend is to favor unchecked exceptions because checked exceptions hurt composability and leak into APIs.

  • Checked exceptions:

    • Subclasses of Exception (not RuntimeException); the compiler forces a try/catch or a throws clause.

    • Intended for conditions a well-written caller can recover from (e.g. IOException).

  • Unchecked exceptions:

    • Subclasses of RuntimeException (or Error); no compiler enforcement.

    • Signal bugs or violated contracts (e.g. NullPointerException, IllegalArgumentException).

  • The modern architectural trend: favor unchecked:

    • Checked exceptions break encapsulation: they propagate up the call stack and pollute every signature in between.

    • They don't compose with lambdas/streams, since functional interfaces don't declare them.

    • Frameworks like Spring wrap checked low-level errors (e.g. SQLException) in unchecked ones (DataAccessException), letting callers handle them only where they can act.

Q46.
What is the conceptual difference between a checked and an unchecked exception, and why is there a trend in modern Java libraries to favor RuntimeException?

Mid

Conceptually, a checked exception models an expected, recoverable failure that the caller must consciously deal with, while an unchecked exception models a programming defect or an unrecoverable state. Modern libraries lean toward RuntimeException because checked exceptions impose a compile-time burden that scales badly and clashes with functional style.

  • The conceptual split:

    • Checked: "this can reasonably fail at runtime, plan for it" (network down, file missing).

    • Unchecked: "the code is wrong" (bad argument, null dereference) and shouldn't normally be caught.

  • Why the shift to RuntimeException:

    • Leaky abstraction: a checked exception forces every intermediate method to declare or wrap it, coupling layers together.

    • Lambda incompatibility: Function, Stream operations can't propagate checked exceptions cleanly.

    • Boilerplate: developers often respond with empty or rethrowing catch blocks, which adds noise without value.

  • Pragmatic guidance: use unchecked for most failures; reserve checked exceptions for cases where the immediate caller truly has a recovery strategy.

Q47.
What is the difference between an Interface and an Abstract Class in Java 17+ (considering default/private methods)?

Mid

With default, static, and private methods, interfaces can now carry behavior, narrowing the gap with abstract classes. The core distinction remains: an interface defines a contract a type can implement many of (no state), while an abstract class is a partial implementation in a single-inheritance hierarchy that can hold mutable state and constructors.

  • State and fields:

    • Interface fields are implicitly public static final (constants only): no instance state.

    • Abstract class can have instance fields, mutable state, and constructors.

  • Inheritance model: A class can implement many interfaces but extend only one abstract class.

  • Method capabilities (Java 17+):

    • Interfaces support default methods (shared behavior), static methods, and private helper methods, but all are implicitly public (except private helpers).

    • Abstract classes support the full range of access modifiers (protected, package-private) and can declare protected non-abstract methods.

  • When to choose:

    • Interface: define a capability or contract for unrelated types.

    • Abstract class: share state plus a partial implementation among closely related types.

Q48.
What is the 'Diamond Problem' in multiple inheritance, and how does Java solve it with Interfaces?

Mid

The Diamond Problem is the ambiguity that arises when a type inherits the same member from two parents that share a common ancestor: the compiler can't tell which version to use. Java avoids it for state by banning multiple class inheritance, and resolves it for behavior (default methods) with explicit conflict-resolution rules.

  • The problem:

    • If B and C both inherit from A and override a method, then D extending both has two candidate implementations: which wins?

    • With mutable state it's worse, since you'd inherit duplicate fields.

  • How Java avoids it:

    • A class can extend only one class, so there's no diamond of state.

    • Interfaces carry no instance state, so implementing many is safe.

  • Resolving default-method conflicts:

    • If two interfaces give conflicting default methods, the class must override the method to break the tie.

    • It can delegate explicitly with InterfaceName.super.method().

java

interface A { default String hi() { return "A"; } } interface B { default String hi() { return "B"; } } class C implements A, B { public String hi() { return A.super.hi(); } // must resolve }

Q49.
With the introduction of default and static methods in interfaces, is there still a reason to use an abstract class?

Mid

Yes, abstract classes are still relevant. Default and static methods let interfaces share behavior, but they cannot hold mutable instance state, define constructors, or use non-public access. Abstract classes remain the right tool when related types must share state and a controlled construction process.

  • What interfaces still can't do:

    • Hold instance fields / mutable state (only public static final constants).

    • Declare constructors to enforce invariants at creation.

    • Use protected or package-private members; default methods are always public.

  • Where abstract classes win:

    • Template Method pattern: shared algorithm skeleton with protected hooks plus shared state.

    • A common base that maintains fields all subclasses rely on.

  • Use interfaces for contracts and capability mixins; use abstract classes when stateful, tightly related types share an implementation backbone.

Q50.
Explain the difference between 'Composition' and 'Inheritance.' Why is the industry moving toward 'Composition over Inheritance'?

Mid

Inheritance models an "is-a" relationship by extending a base class, while composition models a "has-a" relationship by holding other objects and delegating to them. The industry favors composition because it produces looser coupling, more flexibility, and avoids the fragility of deep class hierarchies.

  • Inheritance (is-a):

    • A subclass binds tightly to its parent's implementation at compile time.

    • Fragile base class problem: a change in the parent can silently break subclasses.

  • Composition (has-a):

    • A class holds references to collaborators and delegates work to them.

    • Behavior can change at runtime by swapping the collaborator (the basis of dependency injection and strategy).

  • Why composition is preferred:

    • You depend on small interfaces, not a rigid hierarchy, so code is easier to test and mock.

    • Avoids exposing/inheriting unwanted members from a parent.

    • Many languages and design guides ("favor composition over inheritance") treat inheritance as appropriate only for genuine subtype relationships.

java

// Composition: Car has-an Engine, not extends Engine class Car { private final Engine engine; // swappable collaborator Car(Engine engine) { this.engine = engine; } void start() { engine.run(); } // delegate }

Q51.
Why is 'composition over inheritance' a recommended practice in Java, and what are the risks of deep inheritance hierarchies in large-scale systems?

Mid

Composition models a has-a relationship by holding references to collaborators, while inheritance models is-a. Composition is preferred because it gives looser coupling, runtime flexibility, and avoids the fragility that deep inheritance trees introduce in large systems.

  • Composition is more flexible:

    • Behavior can be swapped at runtime by injecting a different collaborator (think strategy pattern); inheritance is fixed at compile time.

    • You expose only the methods you choose to delegate, not an entire parent API.

  • Inheritance breaks encapsulation: A subclass depends on the parent's internal implementation; changing the parent can silently break subclasses (the fragile base class problem).

  • Risks of deep hierarchies:

    • Hard to reason about: behavior is scattered across many levels and resolved by dynamic dispatch.

    • Rigid: Java has single class inheritance, so one base choice forecloses others.

    • Encourages improper is-a relationships just to reuse code.

  • Guideline: inherit only for true subtype relationships; otherwise compose. Favor interfaces for polymorphism plus composition for reuse.

Q52.
What are the different types of nested classes in Java (static nested, inner, local, anonymous) and how do they differ?

Mid

Java has four kinds of nested classes; the key distinction is whether the nested type holds an implicit reference to an enclosing instance and where it can be declared.

  • Static nested class: Declared with static; no link to an outer instance, so it can be created independently and only accesses the outer class's static members.

  • Inner (non-static member) class: Tied to an enclosing instance; can access all outer fields including private ones. Needs an outer instance to construct: outer.new Inner().

  • Local class: Declared inside a method/block; scoped to that block and can capture effectively final local variables.

  • Anonymous class: A local class with no name, declared and instantiated in one expression, usually to implement an interface or extend a class inline (often replaced today by lambdas).

  • Memory note: inner/local/anonymous classes keep a reference to the enclosing instance, which can cause unintended retention (memory leaks) if held long-term.

Q53.
How are enums implemented in Java, and why is an enum considered the best way to implement a singleton?

Mid

An enum is compiled into a final class extending java.lang.Enum, with each constant a public static final instance created once at class load. That guaranteed single-instantiation makes it the safest singleton implementation.

  • How enums are implemented:

    • The compiler generates a class extending Enum; constants are static final fields initialized in a static block.

    • They can have fields, constructors, and methods, and even per-constant method bodies.

  • Why enum is the best singleton:

    • Serialization-safe: the JVM guarantees enum deserialization returns the same instance, unlike a normal class where readResolve must be added manually.

    • Reflection-safe: you cannot instantiate an enum via reflection (the constructor throws).

    • Thread-safe by construction: instance creation happens at class load, no double-checked locking needed.

java

public enum Config { INSTANCE; private final Properties props = load(); public Properties get() { return props; } } // usage: Config.INSTANCE.get();

Q54.
Why are Strings immutable in Java? Mention security and performance reasons.

Mid

Strings are immutable in Java: once created, the underlying character data never changes, and any "modification" returns a new String. This design supports security, caching, thread-safety, and the String Pool.

  • Security reasons:

    • Strings carry sensitive parameters: file paths, URLs, class names, DB connection strings. If mutable, a value validated then changed (a time-of-check-to-time-of-use attack) could bypass security checks.

    • Safe to share across trusted and untrusted code without defensive copying.

  • Performance reasons:

    • Enables the String Pool: literals can be shared because no one can mutate them.

    • hashCode() is cached on first computation, making Strings excellent HashMap keys.

    • Inherently thread-safe, so they can be shared between threads without synchronization.

  • Trade-off: heavy concatenation creates many temporary objects; use StringBuilder for that.

Q55.
Explain the 'String Templates' feature in Java 21. How does it improve security compared to simple string concatenation?

Mid

String Templates (a preview feature in Java 21 via JEP 430) let you embed expressions inside a template and run them through a template processor that decides how to combine the literal text with the values. Because a processor receives the literal fragments and the interpolated values separately, it can validate or escape inputs, preventing injection that naive concatenation allows.

  • Syntax and processors:

    • Written as PROCESSOR."text \{expr} more"; the built-in STR processor just interpolates to a String.

    • Custom processors (e.g. for SQL or HTML) can sanitize each \{...} value before assembling the result.

  • Why it is safer than concatenation:

    • Plain "... " + userInput + " ..." blindly merges untrusted data into the final string, enabling SQL/HTML injection.

    • A template processor sees the gaps and values distinctly, so it can quote, escape, or parameterize each value before building output.

  • Note: this is a preview feature and its API has since evolved; the security gain depends on using a processor that actually validates input.

java

String name = "Dale"; // STR interpolates String s = STR."Hello \{name}, sum=\{1 + 2}"; // A custom SQL processor could safely escape \{name}

Q56.
Why are Strings immutable in Java? Explain the security and performance implications of the String Pool.

Mid

Strings are immutable: their character data is fixed at creation, so any change produces a new String. This immutability is precisely what makes the String Pool both possible and safe, with strong security and performance benefits.

  • The String Pool and its dependence on immutability:

    • Identical literals share a single pooled instance to save memory; this only works because no holder can mutate the shared object.

    • If Strings were mutable, one reference changing the value would corrupt every other reference to the pooled instance.

  • Security implications:

    • Sensitive values (paths, hostnames, credentials passed as parameters) cannot be altered after a security check, blocking time-of-check-to-time-of-use attacks.

    • Shared pooled strings can be passed around without defensive copies.

  • Performance implications:

    • Cached hashCode() makes Strings fast, reliable HashMap keys.

    • Thread-safe sharing with no synchronization; reduced allocation for repeated literals.

  • Caveat: sensitive secrets like passwords are often better in char[] so they can be zeroed out, since pooled Strings linger in memory until GC.

Q57.
Why is the String Pool critical for Java's memory management, and why was the decision made to keep Strings immutable?

Mid

The String Pool lets the JVM reuse identical string literals instead of allocating a new object for each, saving heap memory; immutability is what makes that sharing safe.

  • The String Pool (interning):

    • String literals are stored in a special pool; identical literals point to one shared instance, so "a" == "a" is true.

    • Saves memory because strings are extremely common; you can force pooling with intern().

  • Why immutability enables this: If one reference could mutate a shared pooled string, every other holder would see the change: catastrophic. Immutability makes sharing safe.

  • Other benefits of immutability:

    • Thread safety: immutable objects need no synchronization.

    • Safe as hash keys: the hash code is cached and never changes.

    • Security: strings used for filenames, URLs, and credentials can't be altered after validation.

Q58.
How do you make a class truly immutable in Java, and what are the benefits of immutability in a multithreaded environment?

Mid

Make a class immutable by preventing any change after construction: a final class, final private fields set once, no setters, and defensive copies of mutable inputs and outputs; such objects are inherently thread-safe.

  • How to make it immutable:

    1. Declare the class final so it can't be subclassed and weakened.

    2. Make all fields private final and set them only in the constructor.

    3. Provide no setters or any mutating methods.

    4. Defensively copy mutable fields on the way in (constructor) and out (getters), so callers can't mutate internal state.

  • Benefits in multithreading:

    • No synchronization needed: state never changes, so there are no race conditions.

    • Safely shareable and freely cacheable across threads.

    • Safe hash keys and good for final publication guarantees.

java

public final class Period { private final Date start; public Period(Date start) { this.start = new Date(start.getTime()); // defensive copy in } public Date getStart() { return new Date(start.getTime()); // defensive copy out } }

Q59.
If you override equals(), why must you also override hashCode()? What happens if two unequal objects have the same hash code in a HashSet?

Mid

You must override hashCode() so equal objects share a bucket; if two UNequal objects happen to share a hash code, that's a legal collision and the collection simply uses equals() to keep them apart.

  • Why override both: The contract demands equal objects have equal hash codes; otherwise lookups miss because objects land in different buckets.

  • Collisions are normal and handled:

    1. Both objects map to the same bucket.

    2. The bucket holds a chain (or tree); equals() distinguishes the entries.

    3. Since they aren't equal, both are correctly stored as separate elements.

  • Performance note: Too many collisions degrade lookup toward O(n) (Java 8+ converts long buckets to balanced trees, O(log n)). A good hashCode() spreads values evenly.

Q60.
What is the difference between a shallow copy and a deep copy, and what are the pitfalls of the Cloneable interface and Object.clone()?

Mid

A shallow copy duplicates the object but shares references to its nested objects, while a deep copy recursively copies those nested objects too; Cloneable and Object.clone() are a famously awkward, error-prone way to do either.

  • Shallow vs deep:

    • Shallow: new top-level object, but inner mutable fields point to the SAME objects, so mutating one copy's nested object affects the other.

    • Deep: inner objects are copied recursively, so the two graphs are fully independent.

  • Pitfalls of Cloneable / clone():

    • Cloneable is a marker interface with no clone() method; the actual method is protected on Object: unintuitive.

    • Default clone() does a shallow copy, so you must manually deep-copy mutable fields.

    • It bypasses constructors and doesn't play well with final fields.

  • Preferred alternatives:

    • A copy constructor or static factory (new Foo(other)): clearer and safer.

    • Or favor immutability so copying is unnecessary.

Q61.
What is autoboxing and unboxing, and why can comparing two Integer objects with '==' give surprising results due to the Integer cache?

Mid

Autoboxing is the automatic conversion of a primitive to its wrapper (int to Integer), and unboxing is the reverse. Comparing two Integer objects with == compares references, and the Integer cache makes small values share instances, so results differ depending on the number.

  • Boxing/unboxing: Done by the compiler via Integer.valueOf(int) and intValue().

  • The Integer cache:

    • valueOf caches values in the range -128 to 127, so boxing the same small value returns the same cached object.

    • Outside that range a new object is created each time.

  • Why == surprises you: Integer a = 100, b = 100; a == b is true (cached), but with 200 it is false.

  • Rule: always use equals() (or compare unboxed primitives) for wrapper values. Also, unboxing a null wrapper throws NullPointerException.

java

Integer a = 100, b = 100; System.out.println(a == b); // true (cached) Integer c = 200, d = 200; System.out.println(c == d); // false (new objects) System.out.println(c.equals(d)); // true

Q62.
What is the difference between BigDecimal and double, and when should you avoid floating-point types for calculations?

Mid

double is a binary (base-2) floating-point type that is fast but approximate, while BigDecimal represents exact decimal values with arbitrary precision. Avoid floating-point whenever exactness matters, especially money.

  • double / float are binary approximations:

    • Many decimal fractions (like 0.1) cannot be represented exactly, so 0.1 + 0.2 yields 0.30000000000000004.

    • Fast (hardware-supported) and fixed 64/32-bit size, good for scientific or performance-sensitive math where small error is acceptable.

  • BigDecimal is exact and arbitrary-precision:

    • Stores an unscaled value plus a scale, so decimal arithmetic is precise.

    • Slower and more memory-heavy; it is immutable so operations return new instances.

    • Always construct from a String: new BigDecimal("0.1"), not from a double, or you inherit the double's error.

  • When to avoid floating-point:

    • Money, financial, tax, billing calculations: use BigDecimal (or integer cents).

    • Anywhere exact equality or rounding rules matter.

  • Never compare BigDecimals with equals() for numeric equality (it considers scale); use compareTo().

java

// Wrong: inherits binary error new BigDecimal(0.1); // 0.1000000000000000055511... // Right: exact new BigDecimal("0.1").add(new BigDecimal("0.2")); // 0.3

Q63.
Are Java Streams 'lazy'? What does that mean for performance?

Mid

Yes. Streams are lazy: intermediate operations build up a pipeline but do no work until a terminal operation is invoked. This lets the runtime fuse operations and short-circuit, avoiding wasted computation.

  • Nothing runs without a terminal op: A chain of filter().map() with no collect() or forEach() does literally nothing.

  • Loop fusion (single pass): Elements flow one at a time through the whole pipeline, so multiple intermediate steps don't each create a new full collection.

  • Short-circuiting: Operations like findFirst(), limit(), anyMatch() can stop early without processing all elements, which also makes infinite streams usable.

  • Performance takeaway: laziness avoids materializing intermediate collections and skips unnecessary work, but the benefit comes from a well-ordered pipeline (e.g. filter before map).

Q64.
Explain the difference between intermediate and terminal operations in the Stream API, and why are Streams considered 'lazy'?

Mid

Intermediate operations return a new stream and are chainable (e.g. map(), filter()); terminal operations produce a result and end the pipeline (e.g. collect(), count()). Streams are 'lazy' because intermediates do no work until a terminal operation triggers the pipeline.

  • Intermediate vs terminal:

    • Intermediate: returns Stream, lazy, can be chained (filter, map, sorted).

    • Terminal: returns a value or side effect, eager, consumes the stream (reduce, forEach, collect).

  • Why laziness matters:

    • Pipeline elements are processed in a single fused pass instead of one full pass per operation.

    • Short-circuiting ops (findFirst, limit, anyMatch) can stop early and even consume infinite streams.

    • Avoids creating intermediate collections, saving memory and CPU.

java

// Nothing executes here: no terminal op Stream<String> s = list.stream().filter(x -> { System.out.println(x); return true; }); // Only on collect() does filter actually run s.collect(Collectors.toList());

Q65.
What is the primary purpose of the Optional class, and why is it generally discouraged to use Optional as a method parameter or a class field?

Mid

The primary purpose of Optional is to model a return value that may legitimately be absent, forcing the caller to consciously handle the "no result" case instead of returning a bare null that triggers a surprise NullPointerException.

  • Its design intent is a return type: It documents in the signature that absence is a valid outcome, and the API (map, orElse, ifPresent) nudges callers to deal with it.

  • Why not a method parameter: It forces callers to wrap arguments (Optional.of(x)), adds noise, and a parameter can still be passed null, so it doesn't even remove the null check. Use overloads or a nullable parameter instead.

  • Why not a class field: Optional is not Serializable, costs an extra heap allocation per field, and multiplies states (present-value, present-empty, the field itself null).

  • Rule of thumb: Return Optional from methods that may find nothing; keep it out of fields, parameters, and collections (use an empty collection instead).

Q66.
What are the tradeoffs of using Java Streams? In what specific scenarios would a traditional for loop be more performant?

Mid

Streams trade a small amount of raw performance for far more readable, composable, declarative pipelines; a plain for loop usually wins for simple, hot, tight iterations because it avoids per-element object and lambda overhead.

  • Benefits of streams: Readable, chainable operations; lazy evaluation; easy switch to parallelism; less boilerplate and fewer mutable index errors.

  • Costs of streams: Each stage allocates lambdas/iterators, boxing of primitives unless you use IntStream/LongStream, harder to debug stack traces, and no easy early break/continue.

  • Where a for loop is more performant:

    1. Tight numeric loops over primitives (boxing costs dominate).

    2. Very small collections where setup overhead outweighs the work.

    3. Hot paths called millions of times where you need to break early or mutate index state.

  • Practical stance: Prefer streams for clarity; drop to loops only when profiling proves a bottleneck.

Q67.
Explain the 'lazy evaluation' of Java Streams. Why won't an intermediate operation like filter() execute until a terminal operation is called?

Mid

Stream intermediate operations are lazy: they only build up a description of the pipeline and return a new stream, doing no actual work until a terminal operation (like collect or forEach) demands results and pulls elements through.

  • Intermediate vs terminal: Intermediate ops (filter, map) return a stream and register behavior; terminal ops (collect, count, reduce) trigger execution.

  • Why laziness matters:

    • It enables fusion: elements flow one at a time through the whole chain, so filter+map are applied per element in a single pass rather than building intermediate collections.

    • It enables short-circuiting: findFirst or limit can stop early without processing the rest, even infinite streams.

  • Consequence: A pipeline with no terminal operation does nothing at all (a common bug). Streams are also single-use: once consumed, you must build a new one.

Q68.
Why is it considered a 'code smell' to use Optional.get() without isPresent()? When should you use Optional as a return type versus a method parameter?

Mid

Calling Optional.get() without first checking presence is a code smell because it throws NoSuchElementException on an empty value: it reintroduces exactly the unchecked failure Optional was meant to prevent, just with a different exception. Use Optional as a return type, not a parameter.

  • Why bare get() is a smell: It's an unguarded unwrap; if empty it blows up like a null deref would have, defeating the point of Optional.

  • Better alternatives: Prefer orElse, orElseGet, orElseThrow, map, or ifPresent so the empty case is handled explicitly.

  • Return type vs parameter:

    • Return type: ideal for "may find nothing" methods (lookups, finds), signaling absence in the signature.

    • Parameter: avoid it; use method overloads or a plain nullable argument, since the caller can still pass null and the wrapping just adds noise.

java

// Smell Optional<User> u = repo.findById(id); return u.get(); // throws if empty // Better return repo.findById(id) .orElseThrow(() -> new UserNotFound(id));

Q69.
How do Collectors work in the Stream API, and how would you use groupingBy or partitioningBy?

Mid

A Collector is a mutable reduction strategy: it tells collect() how to supply a container, accumulate each element into it, combine partial containers (for parallelism), and optionally finish the result. groupingBy buckets elements into a Map by a key function, and partitioningBy is a specialized two-bucket split by a predicate.

  • How a Collector works: Defined by four functions: supplier, accumulator, combiner, finisher; the factory class Collectors provides ready-made ones (toList, toMap, joining, counting).

  • groupingBy: Produces a Map<K, List<T>> by default; a second argument is a downstream collector to reduce each group (count, sum, map values).

  • partitioningBy: Always returns a Map<Boolean, List<T>> with both true and false keys present, even if a side is empty; use it when the split is a single boolean test.

java

// group employees by department Map<String, List<Employee>> byDept = emps.stream().collect(Collectors.groupingBy(Employee::getDept)); // group + downstream: count per department Map<String, Long> countByDept = emps.stream().collect( Collectors.groupingBy(Employee::getDept, Collectors.counting())); // partition by a predicate Map<Boolean, List<Employee>> partition = emps.stream().collect( Collectors.partitioningBy(e -> e.getSalary() > 100_000));

Q70.
What is the difference between map() and flatMap() in the Stream API?

Mid

Both transform elements of a stream, but map() produces one output per input while flatMap() produces a stream per input and flattens them all into one stream.

  • map() is one-to-one:

    • Applies a function to each element, returning a stream of the same size: Stream<T> -> Stream<R>.

    • If the function itself returns a collection or stream, you end up with a Stream<Stream<R>> (nested).

  • flatMap() is one-to-many then flattened:

    • The mapper returns a Stream for each element, and flatMap() concatenates them into a single flat stream.

    • Use it to merge nested structures, e.g. a list of lists into one stream of elements.

  • Rule of thumb: use map() to transform values, use flatMap() to both transform and unwrap/flatten nested streams.

java

List<List<Integer>> nested = List.of(List.of(1,2), List.of(3,4)); // map -> Stream<Stream<Integer>> (nested, usually not what you want) nested.stream().map(List::stream); // flatMap -> Stream<Integer> [1,2,3,4] List<Integer> flat = nested.stream() .flatMap(List::stream) .collect(Collectors.toList());

Q71.
Why must local variables captured by a lambda or anonymous class be final or effectively final?

Mid

Because a lambda or anonymous class captures the variable's value, not a live reference to the stack slot: requiring it to be final or effectively final guarantees the captured copy can never diverge from the original.

  • Capture is by value: Local variables live on the thread's stack, which disappears when the method returns, but the lambda may outlive it, so the JVM copies the value into the lambda instance.

  • Mutability would break consistency: If the original could change after capture, the copy and the original would silently disagree, so the language forbids it.

  • "Effectively final" relaxes the syntax: Since Java 8 you don't need the final keyword: a variable that is never reassigned after initialization qualifies automatically.

  • Thread-safety benefit: Immutable captured state avoids data races when the lambda runs on another thread.

  • Workaround: to mutate, capture a mutable container (an array, an AtomicInteger, or a field) whose reference stays final.

Q72.
How do Java Records differ from standard POJOs, and why are they considered 'transparent carriers' of data?

Mid

Records are immutable, named tuples whose state is fully defined by their components: the compiler generates the constructor, accessors, equals(), hashCode(), and toString() so the data is exposed exactly as declared, hence "transparent carriers."

  • What a record auto-generates: A canonical constructor, a private final field and an accessor per component, plus value-based equals()/hashCode()/toString().

  • Immutable by design: Components are final, so a record cannot be mutated after construction, unlike a typical POJO with setters.

  • "Transparent carrier" meaning: The public API (the accessors) directly mirrors the internal state: what you put in is exactly what you read out, with no hidden representation.

  • Constraints vs POJOs: Records implicitly extend java.lang.Record and cannot extend another class, but they can implement interfaces.

java

public record Point(int x, int y) { } // equivalent POJO would need ~30 lines of constructor, // getters, equals, hashCode, toString boilerplate

Q73.
Explain Pattern Matching for switch. How does it improve upon the traditional switch statement?

Mid

Pattern Matching for switch lets case labels match the type (and shape) of the selector and bind a typed variable in one step, turning long if-else instanceof chains into concise, exhaustive switches.

  • Type patterns in case labels: case String s both tests the type and binds s, removing the explicit cast.

  • Guards refine matches: A when clause adds a boolean condition: case Integer i when i > 0.

  • Exhaustiveness and null handling:

    • Over a sealed type or enum the compiler enforces coverage of all cases.

    • A case null label can handle null explicitly instead of throwing NullPointerException.

  • Improvements over traditional switch:

    • Old switch worked only on constants (ints, enums, strings) and fell through by default.

    • Arrow syntax -> avoids fall-through and switch can be used as an expression returning a value.

java

String describe(Object obj) { return switch (obj) { case Integer i when i > 0 -> "positive int " + i; case Integer i -> "non-positive int " + i; case String s -> "string of length " + s.length(); case null -> "null"; default -> "something else"; }; }

Q74.
What is the purpose of 'Unnamed Patterns and Variables' in Java 21?

Mid

Unnamed patterns and variables (a preview in Java 21) use the underscore _ to mark a binding or variable you must declare but never use, making intent explicit and removing distracting names.

  • Unnamed variables: Used where a variable is syntactically required but irrelevant: a catch exception you ignore, a loop counter, or a side-effecting assignment.

  • Unnamed patterns: In record deconstruction, _ matches and ignores a component you don't care about, e.g. case Point(int x, _).

  • Why it matters:

    • Signals "intentionally unused" to readers and tools, reducing noise and avoiding fake names like ignored.

    • Multiple _ can appear in the same scope without name-clash errors, which ordinary variables can't.

java

try { process(); } catch (NumberFormatException _) { // exception unused return -1; } // ignore second component of a record pattern if (obj instanceof Point(int x, _)) { use(x); }

Q75.
What is the purpose of a sealed class, and how does it improve the security or maintainability of a class hierarchy?

Mid

A sealed class restricts which other classes may extend or implement it via a permits clause, giving the author precise control over the hierarchy and letting the compiler reason about a closed set of subtypes.

  • Controlled extension: Only the listed classes can extend a sealed type, so no external code can inject an unexpected subtype.

  • Each permitted subclass must be marked: It must be final (no further extension), sealed (continues the restriction), or non-sealed (reopens it).

  • Security benefit: Prevents malicious or accidental subclasses that could break invariants, similar in spirit to final but allowing a known family.

  • Maintainability benefit: The hierarchy is documented in one place and enables exhaustive switch / pattern matching, so adding a subtype forces you to update all dependent logic.

java

public sealed interface Shape permits Circle, Square { } public final class Circle implements Shape { } public final class Square implements Shape { }

Q76.
What are Java Records, and why are they considered more than just 'syntactic sugar' for POJOs?

Mid

Records are a special class form for immutable data aggregates: declaring components generates the constructor, accessors, and value-based equals()/hashCode()/toString(). They're more than sugar because they introduce real semantic guarantees the compiler and JVM rely on.

  • More than boilerplate removal:

    • A record is a distinct nominal type extending java.lang.Record, with an enforced contract: its state is exactly its components.

    • equals() is guaranteed value-based across all components, a semantic promise a hand-written POJO can't make to the compiler.

  • Enables language features: Record deconstruction patterns (case Point(int x, int y)) work precisely because the component structure is known and transparent.

  • Customizable where it matters: You can add a compact canonical constructor for validation, or override accessors, while keeping immutability.

  • Constraints reinforce intent: Components are final and a record cannot extend another class, signaling it is purely a data carrier.

java

public record Range(int lo, int hi) { public Range { // compact constructor: validation if (lo > hi) throw new IllegalArgumentException("lo > hi"); } }

Q77.
Explain how Pattern Matching for switch and instanceof changes the way we handle complex conditional logic.

Mid

Pattern matching lets you test a type and bind it to a typed variable in one step, eliminating the test-cast-assign ritual and turning nested if-else chains into flat, exhaustive switches that the compiler can verify.

  • Pattern matching for instanceof:

    • Combines the type check and cast: if (obj instanceof String s) binds s in scope when the test passes.

    • Removes the redundant explicit cast and the bug surface that comes with it.

  • Pattern matching for switch:

    • Switch can match on type patterns, not just constants, replacing long if/else-if cascades over subtypes.

    • Supports guards via when clauses to add conditions to a case.

  • Compiler-enforced safety:

    • With sealed hierarchies the compiler checks exhaustiveness: forget a case and it won't compile.

    • Explicit null handling becomes a case rather than a hidden NPE.

  • Net effect: logic shifts from imperative branching to declarative, data-driven decomposition that reads like the problem.

java

Object o = ...; String result = switch (o) { case Integer i when i > 10 -> "big int"; case Integer i -> "small int"; case String s -> "string: " + s; case null -> "null"; default -> "other"; };

Q78.
Why are Records considered 'transparent carriers' of data, and how does this differ from a standard class?

Mid

A record is a "transparent carrier" because its API is its state: the components you declare in the header fully define what it holds, and the language derives the accessors, constructor, equals, hashCode, and toString directly from them. Nothing is hidden behind the data.

  • State and API are the same thing: The header record Point(int x, int y) declares both the fields and the public accessors x() and y().

  • Generated semantics follow the components:

    • equals and hashCode compare all components (value semantics), and toString prints them.

    • Deconstruction patterns work precisely because the components are public and ordered.

  • How a standard class differs:

    • It can hold hidden mutable state, derive fields, or expose getters that don't map to its real internals (opaque encapsulation).

    • You must hand-write or generate equals/hashCode/toString, and they can drift out of sync with the fields.

  • Trade-off: Transparency is ideal for plain data; it's the wrong tool when you need to hide representation or enforce invariants beyond a compact constructor check.

Q79.
Explain 'Pattern Matching for switch.' How does it change the way we handle complex object hierarchies?

Mid

Pattern matching for switch lets a switch test the runtime type (and structure) of its selector and bind matched data in each branch, so you decompose an object hierarchy declaratively in one construct instead of cascading type checks.

  • Type patterns replace if-else chains: Each case matches a subtype and binds a typed variable, ready to use in that arm.

  • Record (deconstruction) patterns: You can destructure components inline, e.g. case Point(int x, int y), and even nest patterns for deep structures.

  • Guards refine matches: A when clause adds a boolean condition without breaking exhaustiveness analysis.

  • Exhaustiveness over hierarchies:

    • Over a sealed hierarchy the compiler verifies every subtype is covered, often removing the need for default.

    • null can be handled as an explicit case rather than crashing.

  • Effect on design: Behavior can live outside the classes in a focused switch, which is convenient when operations change more often than the data shapes.

Q80.
Why should you use a Record instead of a standard class for a DTO, and what are the implications for inheritance and immutability?

Mid

Use a record for a DTO because it gives you an immutable, value-based data holder with correct equals/hashCode/toString for free, removing boilerplate and intent ambiguity. The trade-offs are real: records are final, can't extend classes, and are shallowly immutable.

  • Why a record fits a DTO:

    • DTOs are pure data; the record's transparent components match that role exactly.

    • Value-based equals makes them safe as map keys and easy to compare/test.

    • A compact constructor lets you validate or normalize inputs.

  • Immutability implications:

    • All components are final; you create a new instance to "change" data.

    • Immutability is shallow: a component that is a mutable List can still be mutated, so defensively copy in the canonical constructor if needed.

  • Inheritance implications:

    • A record is implicitly final and cannot extend another class (it already extends java.lang.Record).

    • It can still implement interfaces, which is how it joins a sealed hierarchy.

  • When not to use one: You need hidden/derived state, mutability, or a class-based inheritance hierarchy.

Q81.
Explain how 'Pattern Matching for switch' changes the way we handle complex object hierarchies compared to the instanceof check.

Mid

Both let you branch on runtime type, but a chain of instanceof checks is open-ended, imperative, and unverified, while a pattern-matching switch is a single, structured construct the compiler can check for exhaustiveness over a hierarchy.

  • The instanceof approach:

    • Reads as a sequential if (x instanceof A a) ... else if (x instanceof B b) ... cascade.

    • No exhaustiveness guarantee: a missed subtype just falls through silently.

    • Order matters and is error-prone (a supertype case can shadow a subtype).

  • The switch approach:

    • One declarative expression that can also return a value via arrow cases.

    • Supports deconstruction (record patterns), guards (when), and explicit null cases.

    • Over a sealed hierarchy it is checked exhaustive: a new subtype breaks the build until handled.

  • Bottom line: instanceof suits an occasional single check; switch patterns suit dispatching over a whole object hierarchy safely.

Q82.
What does the 'volatile' keyword actually guarantee regarding visibility and instruction reordering?

Mid

volatile guarantees visibility (a write is immediately seen by other threads, never cached locally) and ordering (it prevents certain reorderings around the volatile access), but it does NOT make compound operations atomic.

  • Visibility guarantee: A write to a volatile field is flushed to main memory and reads always go to main memory, so threads never see a stale cached value.

  • Ordering / reordering guarantee:

    • Acts as a memory barrier: writes before a volatile write are not reordered after it, and reads after a volatile read are not reordered before it.

    • Establishes a happens-before edge: everything visible to the writing thread before the volatile write becomes visible to a thread that later reads it.

  • What it does NOT guarantee: Atomicity of read-modify-write: count++ is read, increment, write (three steps) and can still race.

  • Good use case: A simple flag written by one thread and read by others (e.g. a volatile boolean running stop signal).

Q83.
What is the difference between 'synchronized' and 'ReentrantLock'? When would you prefer the latter?

Mid

Both provide mutual exclusion and reentrancy, but synchronized is a built-in JVM construct with automatic lock release, while ReentrantLock is an explicit API offering more control (timed/interruptible acquisition, fairness, multiple conditions) at the cost of manual unlocking.

  • synchronized:

    • Intrinsic lock managed by the JVM; lock is released automatically on block exit or exception.

    • Simpler and less error-prone, but blocking is uninterruptible and you cannot try-then-give-up.

  • ReentrantLock:

    • Explicit lock() / unlock(); you must unlock in a finally block.

    • Adds tryLock() (with timeout), lockInterruptibly(), optional fairness, and multiple Condition objects.

  • Prefer ReentrantLock when you need: Try-lock with timeout to avoid deadlock, interruptible waits, fairness ordering, or several wait-sets (conditions) on one lock.

  • Otherwise prefer synchronized: It is cleaner and the JVM cannot leak the lock if you forget to release it.

java

lock.lock(); try { // critical section } finally { lock.unlock(); // must release even on exception }

Q84.
How does a 'Deadlock' occur, and what are the four necessary conditions for it?

Mid

A deadlock occurs when two or more threads each hold a lock the other needs and wait forever, so none can proceed. It requires four conditions to hold simultaneously (Coffman conditions); breaking any one prevents it.

  • Mutual exclusion: At least one resource is held in a non-shareable mode (only one thread at a time).

  • Hold and wait: A thread holds at least one resource while waiting to acquire another.

  • No preemption: A resource cannot be forcibly taken; it is released only voluntarily by the holder.

  • Circular wait: A cycle of threads exists where each waits for a resource held by the next.

  • How to prevent it: Impose a global lock ordering (breaks circular wait), or use tryLock() with timeout (breaks hold-and-wait).

Q85.
What is the difference between the volatile keyword and Atomic variables, and why doesn't volatile guarantee atomicity?

Mid

volatile only guarantees visibility and ordering of a single field, while atomic classes like AtomicInteger add atomic compound operations (read-modify-write) using CAS. volatile fails for things like i++ because that is three separate steps, not one indivisible operation.

  • volatile:

    • Ensures each read sees the latest write and enforces memory barriers, but each operation is independent.

    • Two threads both doing count++ can read the same value and lose an update.

  • Atomic variables:

    • Wrap a volatile value and provide atomic methods (incrementAndGet(), compareAndSet()) backed by hardware CAS instructions.

    • Lock-free: the read-modify-write happens as one indivisible step that retries on contention.

  • Why volatile isn't atomic: Atomicity is about indivisibility of a multi-step action; visibility is about when a value is seen. They are orthogonal, and volatile only solves the latter.

  • Rule of thumb: Single-writer flag: volatile. Concurrent counters/accumulators: an Atomic class or a lock.

Q86.
When would you use ReentrantLock instead of a synchronized block, and what are the trade-offs in terms of fairness and flexibility?

Mid

Use ReentrantLock when you need capabilities synchronized lacks: timed or interruptible lock attempts, fairness, multiple condition variables, or lock acquisition spanning method boundaries. The trade-off is added flexibility versus the responsibility of manual, correct unlocking.

  • Reasons to choose ReentrantLock:

    • tryLock(): acquire only if free (optionally within a timeout), letting you back off instead of blocking forever.

    • lockInterruptibly(): a waiting thread can respond to interruption.

    • Multiple Condition objects on one lock (e.g. separate notFull/notEmpty queues).

  • Fairness trade-off:

    • new ReentrantLock(true) grants the lock in FIFO order, preventing starvation but lowering throughput.

    • The default (non-fair) lock allows barging, which is faster but can starve some threads.

  • Flexibility cost: You must call unlock() in a finally; forgetting it leaks the lock, whereas synchronized releases automatically.

  • Default choice: Stick with synchronized for simple mutual exclusion; reach for ReentrantLock only when you actually need its extra features.

Q87.
How do wait(), notify(), and notifyAll() work, and why must they be called from within a synchronized block?

Mid

wait(), notify(), and notifyAll() are the low-level thread coordination primitives on Object: wait() releases the monitor and suspends the thread until another thread calls notify()/notifyAll() on the same object. They must run inside a synchronized block because they operate on that object's monitor, which the caller must already own.

  • What each does:

    • wait(): releases the lock and parks the thread on the object's wait set.

    • notify(): wakes one arbitrary waiting thread; notifyAll() wakes all of them (they then re-contend for the lock).

  • Why synchronized is mandatory:

    • These methods act on the monitor; calling without owning it throws IllegalMonitorStateException.

    • It also prevents the lost-wakeup race: holding the lock guarantees the condition check and the wait() happen atomically relative to the notifier.

  • Always wait in a loop:

    • Re-check the condition because of spurious wakeups and because the state may change before the woken thread reacquires the lock.

    • Prefer notifyAll() unless you're certain exactly one waiter can proceed.

java

synchronized (queue) { while (queue.isEmpty()) { // loop, not if queue.wait(); // releases lock, suspends } return queue.remove(); } // producer side synchronized (queue) { queue.add(item); queue.notifyAll(); }

Q88.
What is a daemon thread, and how does it differ from a user thread in terms of JVM shutdown?

Mid

A daemon thread is a background service thread (like the GC) that the JVM does not wait for: the JVM exits as soon as all user (non-daemon) threads finish, abruptly terminating any daemon threads still running.

  • User vs daemon at shutdown:

    • The JVM stays alive while at least one user thread runs.

    • When the last user thread ends, the JVM shuts down and kills daemons without letting them complete.

  • Creating one: Call thread.setDaemon(true) before start(); a thread inherits the daemon status of its creator by default.

  • Caveat: Because daemons can be stopped mid-operation, never use them for work that must finish or release critical resources (finally blocks may not run).

Q89.
Explain the 'Metaspace' in Java 8+. How does it differ from the old PermGen?

Mid

Metaspace, introduced in Java 8, is the area that stores class metadata (class structures, method data, etc.), replacing the old PermGen. Its defining change is that it lives in native (off-heap) memory and grows dynamically, rather than being a fixed-size region inside the Java heap.

  • What it stores: Class metadata: the runtime representation of classes, methods, and constant pool information.

  • Differences from PermGen:

    • Location: PermGen was part of the heap with a fixed max (-XX:MaxPermSize); Metaspace uses native memory and auto-expands by default.

    • Tuning: bounded by -XX:MaxMetaspaceSize (unlimited if unset, capped by native memory).

    • Errors: exhaustion throws OutOfMemoryError: Metaspace instead of the old PermGen space error.

  • Why the change: PermGen's fixed size caused frequent OutOfMemoryError in apps that load many classes (heavy frameworks, dynamic class generation); auto-growing Metaspace and better unloading reduce that.

Q90.
How can a memory leak occur in a Java application despite having an automatic Garbage Collector?

Mid

The GC only reclaims objects that are unreachable; a leak happens when the application keeps live references to objects it no longer needs, so they stay reachable forever and accumulate.

  • GC reclaims unreachable, not unused: If any GC root chain still points to an object, it's retained even if the program will never touch it again.

  • Common leak sources:

    • Unbounded collections or caches that grow without eviction.

    • Static fields holding references for the app's whole lifetime.

    • Listeners/callbacks registered but never unregistered.

    • ThreadLocal values not removed, especially on pooled threads.

    • Keys in a HashMap with broken or mutable equals/hashCode.

  • Mitigations: Bound caches (size/time eviction), use WeakReference/WeakHashMap where appropriate, and clean up in finally/close.

Q91.
What is the 'Stop-the-World' phase in GC, and how do modern collectors try to minimize it?

Mid

A Stop-the-World (STW) phase is when the JVM pauses all application threads so the collector can work on a consistent heap snapshot; modern collectors minimize it by doing most work concurrently and keeping only tiny, bounded pauses.

  • Why STW exists:

    • Some operations (root scanning, certain pointer fix-ups) need the object graph to not change mid-operation.

    • All threads pause at safepoints so the GC sees a stable view.

  • How modern collectors shrink it:

    • Concurrent marking: trace live objects while the app runs, using write/load barriers to track changes.

    • Concurrent relocation: ZGC and Shenandoah move objects without stopping threads via barriers.

    • Incremental/region-based work: G1 collects a subset of regions per pause to hit a target pause time.

  • Reality: STW can't be fully eliminated (e.g. initial mark, thread-stack scanning), but ZGC/Shenandoah keep it to a fixed sub-millisecond cost.

Q92.
Explain the concept of Generational Garbage Collection. Why is the heap divided into Young and Old generations?

Mid

Generational GC splits the heap by object age because most objects die young (the 'weak generational hypothesis'); collecting the young area frequently and cheaply, and the old area rarely, makes GC far more efficient.

  • The weak generational hypothesis:

    • The vast majority of objects become garbage shortly after allocation.

    • So a collector that focuses on recent allocations reclaims the most memory for the least work.

  • Young generation:

    • Holds new objects (Eden plus two Survivor spaces); collected often with fast minor GCs.

    • Surviving objects are copied between survivor spaces and aged.

  • Old generation:

    • Holds long-lived objects promoted after surviving enough minor GCs (the tenuring threshold).

    • Collected less frequently; major/full GCs here are more expensive.

  • Benefit: Scanning a small young region repeatedly is cheaper than scanning the whole heap each time.

Q93.
What is the difference between Minor, Major, and Full Garbage Collection, and what triggers a 'Stop-the-World' event?

Mid

Minor GC cleans the young generation, Major GC cleans the old generation, and Full GC cleans the entire heap (plus metaspace); each typically involves some Stop-the-World pause, triggered when a region fills up or the allocator can't satisfy a request.

  • Minor GC:

    • Collects the young generation; triggered when Eden fills.

    • Fast and frequent; always STW but usually short.

  • Major GC:

    • Collects the old generation; triggered as old space fills with promoted objects.

    • Slower because the old gen is larger and objects are long-lived.

  • Full GC:

    • Collects young + old (and metaspace); the most expensive and most disruptive.

    • Triggered by allocation failure, promotion failure, or explicit System.gc().

  • What triggers STW:

    • The collector pauses threads at a safepoint to scan roots and (in older collectors) move objects safely.

    • Concurrent collectors (ZGC, Shenandoah) keep these pauses minimal by doing most work alongside the app.

Q94.
What is Type Erasure in Java Generics, and what limitations does it impose on developers at runtime?

Mid

Type erasure means generic type information exists only at compile time: the compiler checks and then removes type parameters, replacing them with their bounds (or Object), so the runtime has no knowledge of the generic type.

  • How it works:

    • List<String> and List<Integer> both become raw List at runtime.

    • The compiler inserts casts and bridge methods to preserve type safety and polymorphism.

  • Runtime limitations it imposes:

    • No new T() or new T[]: the type isn't known at runtime.

    • instanceof against a parameterized type fails: x instanceof List<String> is illegal.

    • Cannot overload methods that differ only by generic parameter (same erasure clash).

    • Cannot have static fields of the type parameter, nor catch a generic exception type.

  • Why: it was a deliberate choice for backward compatibility so generic and pre-generics code interoperate on the same JVM.

  • Workaround: pass a Class<T> token when runtime type is needed.

Q95.
What is 'Type Erasure' in Generics? Why can't you use primitives as type parameters?

Mid

Type erasure is the compiler's removal of generic type parameters after type checking, leaving raw types at runtime. Primitives can't be type parameters because erasure relies on everything being an Object reference, and primitives are not objects.

  • Erasure replaces T with Object (or its bound), so generic containers store references, not raw primitive values.

  • Why no primitives:

    • int, double, etc. don't extend Object, so they can't fit where an Object reference is expected.

    • You must use wrapper types: List<Integer>, not List<int>.

  • Cost: autoboxing/unboxing creates wrapper objects, adding memory overhead and indirection for primitive-heavy generic code.

Q96.
Explain the PECS (Producer Extends, Consumer Super) principle. When would you use <? extends T> versus <? super T>?

Mid

PECS tells you which wildcard to use based on data flow: <? extends T> for sources you read from (producers), and <? super T> for targets you write into (consumers).

  • Use <? extends T> when the collection produces values:

    • You can safely read elements as T, since each is a subtype of T.

    • You cannot add elements (the exact subtype is unknown).

  • Use <? super T> when the collection consumes values:

    • You can safely add any T or subtype.

    • Reading back yields only Object.

  • Mnemonic in practice: a method that copies from one list to another reads from the producer and writes to the consumer.

java

static <T> void copy(List<? super T> dest, List<? extends T> src) { for (int i = 0; i < src.size(); i++) { dest.set(i, src.get(i)); // read producer, write consumer } }

Q97.
Explain the difference between 'submit()' and 'execute()' in an ExecutorService.

Mid

Both schedule tasks on an ExecutorService, but execute() is fire-and-forget for Runnable, while submit() accepts Runnable or Callable and returns a Future to track the result.

  • execute(Runnable):

    • Returns void; defined on Executor.

    • An uncaught exception propagates to the thread's UncaughtExceptionHandler.

  • submit(...):

    • Returns a Future so you can get the result or cancel.

    • Exceptions are captured inside the Future and re-thrown as ExecutionException when you call get().

  • Key consequence: with submit(), exceptions are silently swallowed unless you inspect the Future; choose it when you need the result, and execute() for simple background work.

Q98.
What is the difference between Future and CompletableFuture, and what limitations of Future does CompletableFuture address?

Mid

Future represents a pending result you can only poll or block on; CompletableFuture extends it with completion callbacks, chaining, and combining, enabling non-blocking asynchronous pipelines.

  • Limitations of Future:

    • No callbacks: you must call get(), which blocks the thread until the result is ready.

    • No chaining: can't transform one result into the next without blocking.

    • No combining of multiple futures, and no built-in exception handling.

    • You can't complete it manually from outside.

  • What CompletableFuture adds:

    • Non-blocking composition: thenApply, thenCompose, thenCombine build pipelines that run when results arrive.

    • Callbacks via thenAccept/thenRun; error handling via exceptionally and handle.

    • Manual completion via complete(), and aggregation with allOf/anyOf.

  • Both implement Future, so CompletableFuture is a drop-in superset.

java

CompletableFuture.supplyAsync(() -> fetchUser(id)) .thenApply(User::getName) .exceptionally(ex -> "unknown") .thenAccept(System.out::println); // never blocks

Q99.
How should you properly shut down an ExecutorService, and what is the difference between shutdown() and shutdownNow()?

Mid

Initiate an orderly shutdown with shutdown(), then wait with awaitTermination(), and fall back to shutdownNow() if tasks don't finish in time. The difference is whether already-submitted tasks are allowed to complete.

  • shutdown(): graceful:

    • Stops accepting new tasks but lets already-submitted tasks (queued and running) finish.

    • Returns immediately; doesn't wait.

  • shutdownNow(): forceful:

    • Attempts to stop running tasks by interrupting them and returns the list of tasks never started (still in the queue).

    • Only works if tasks respond to interruption; uninterruptible loops won't actually stop.

  • Recommended pattern:

    • Call shutdown(), then awaitTermination() with a timeout; if it returns false, call shutdownNow() and await again.

    • Failing to shut down leaks non-daemon threads and can prevent the JVM from exiting.

java

pool.shutdown(); try { if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); pool.awaitTermination(60, TimeUnit.SECONDS); } } catch (InterruptedException e) { pool.shutdownNow(); Thread.currentThread().interrupt(); }

Q100.
What are Virtual Threads (Project Loom) and how do they differ from traditional Platform Threads?

Mid

Virtual threads (JDK 21+) are lightweight threads managed by the JVM rather than the OS, so you can run millions of them. They make blocking I/O cheap by unmounting from a carrier thread instead of holding an OS thread.

  • Platform threads:

    • Thin wrappers over OS threads: each costs ~1MB stack and a kernel resource, so you're limited to a few thousand.

    • Blocking on I/O pins the OS thread, wasting it while it waits.

  • Virtual threads:

    • Scheduled by the JVM onto a small pool of carrier (platform) threads. Cheap to create and have small, growable stacks.

    • On a blocking call, the virtual thread unmounts and frees its carrier for other work, then remounts when ready.

  • Practical impact:

    • Enables a simple thread-per-request style at massive scale without reactive complexity.

    • Create with Thread.ofVirtual() or Executors.newVirtualThreadPerTaskExecutor().

    • They help I/O-bound workloads, not CPU-bound ones (CPU work still needs real cores).

Q101.
What are Virtual Threads, and how do they differ from traditional Platform Threads in terms of resource management?

Mid

Virtual threads are JVM-managed lightweight threads, while platform threads map 1:1 to OS threads. The core difference is resource management: virtual threads decouple the number of concurrent tasks from the number of scarce OS threads.

  • Memory footprint: Platform threads reserve a large fixed stack (~1MB) eagerly; virtual threads use a small, heap-stored stack that grows and shrinks on demand.

  • Scheduling and OS resources:

    • Platform threads are scheduled by the OS kernel and consume a kernel thread each.

    • Virtual threads are scheduled by the JVM onto a small pool of carrier threads, consuming an OS thread only while actually running.

  • Scale and lifecycle:

    • You can have millions of virtual threads but only thousands of platform threads.

    • Virtual threads are cheap and disposable: create one per task rather than pooling them. Don't pool virtual threads.

  • Implication: Blocking a virtual thread releases its carrier, so blocking is no longer expensive for I/O-bound workloads.

Q102.
What is the fundamental difference between a Platform Thread and a Virtual Thread?

Mid

A platform thread is a thin wrapper over a single OS thread (a heavyweight, scarce resource), while a virtual thread is a lightweight, JVM-managed thread that is scheduled onto a small pool of platform threads (carriers) only while it runs.

  • Platform thread:

    • 1:1 mapping to an OS kernel thread; creation and context switches are expensive.

    • Large fixed stack (~1MB), so you can only have thousands before exhausting memory.

    • Blocking it blocks the underlying OS thread.

  • Virtual thread:

    • Managed by the JVM; many virtual threads (millions) multiplexed onto few carrier threads.

    • Cheap to create and discard; stack lives on the heap and grows/shrinks as needed.

    • When it blocks on I/O, the JVM unmounts it and frees the carrier to run others.

  • Design intent: virtual threads make the simple thread-per-request style scale, instead of forcing async/reactive code.

java

Thread.ofVirtual().start(() -> handleRequest()); // virtual Thread.ofPlatform().start(() -> handleRequest()); // platform (OS thread)

Q103.
When would you still prefer a fixed thread pool over virtual threads?

Mid

Prefer a fixed thread pool when the work is CPU-bound or when you deliberately need to limit concurrency against a scarce resource: virtual threads excel at I/O-bound concurrency, not at running more computation than you have cores.

  • CPU-bound workloads: Spawning millions of virtual threads for pure computation just adds scheduling overhead; a pool sized near the core count is optimal.

  • Resource throttling / backpressure:

    • A fixed pool acts as a natural semaphore (e.g. limiting concurrent calls to a database or a legacy service with a small connection pool).

    • Virtual threads provide no built-in limit, so you must add explicit rate limiting yourself.

  • Heavy use of synchronized or native code: Pinning-prone code can negate the benefits, making a classic pool simpler and more predictable.

  • Note: never pool virtual threads themselves: They are cheap and disposable; use newVirtualThreadPerTaskExecutor(), reserving fixed pools for the cases above.

Q104.
What is the fundamental difference between a platform thread and a virtual thread in terms of how they are mapped to the OS?

Mid

A platform thread maps 1:1 to an operating-system thread, so the OS scheduler directly manages it; a virtual thread uses an M:N model where many virtual threads are scheduled by the JVM onto a small set of OS threads (carriers).

  • Platform thread: 1:1:

    • Each is backed by one dedicated kernel thread for its entire life.

    • The OS owns scheduling, blocking, and context switching.

    • Count is limited by OS resources (typically thousands).

  • Virtual thread: M:N:

    • Many (M) virtual threads run over few (N) carrier OS threads, where N defaults to the number of cores.

    • The JVM scheduler (a ForkJoinPool) decides which virtual thread occupies a carrier.

    • A virtual thread holds an OS thread only while actively executing, not while blocked.

  • Consequence: You can have millions of virtual threads because they are decoupled from scarce OS threads.

Q105.
Explain the role of the Bootstrap, Extension, and Application ClassLoaders.

Mid

The JVM loads classes through a delegation hierarchy of three loaders, each responsible for a different source: a loader first delegates to its parent and only loads the class itself if the parent can't, which keeps core classes trustworthy.

  • Bootstrap ClassLoader:

    • Loads core JDK classes (java.lang, java.util, etc.) from the runtime image.

    • Written in native code, it is the root parent and returns null when queried as a parent.

  • Platform / Extension ClassLoader: Loads platform modules beyond the core (in Java 9+ called the Platform ClassLoader; previously the Extension loader).

  • Application / System ClassLoader:

    • Loads your application classes from the classpath/module path.

    • Its parent is the platform loader.

  • Parent-delegation model:

    • Each request goes up to the parent first, preventing user code from shadowing core classes (you can't replace java.lang.String).

    • Enables visibility rules: child loaders see parent classes, not vice versa.

Q106.
What is 'Reflection' and what are the performance and security risks of using it?

Mid

Reflection is the API (mainly java.lang.reflect) that lets code inspect and manipulate classes, methods, and fields at runtime, even invoking or modifying members it doesn't know about at compile time. It is powerful but slower than direct calls and can break safety guarantees.

  • What it does:

    • Discover metadata (Class.getMethods(), fields, annotations) and invoke dynamically (Method.invoke(), Constructor.newInstance()).

    • Backbone of frameworks: Spring DI, Hibernate, Jackson, JUnit.

  • Performance risks:

    • Calls are slower: extra indirection, type checks, autoboxing of arguments, and the JIT can't inline/optimize as well.

    • Cache Method/Field lookups; the lookup itself is the costly part.

  • Security / safety risks:

    • setAccessible(true) can bypass private access, breaking encapsulation and invariants.

    • Errors move from compile time to runtime (NoSuchMethodException), so refactors silently break reflective code.

    • JPMS restricts deep reflection unless a package is opens/open.

Q107.
What is 'Serialization' and what is the role of 'serialVersionUID'?

Mid

Serialization is converting an object's state into a byte stream (and deserialization back into an object), enabled by implementing Serializable. serialVersionUID is a version stamp that the JVM uses to verify that the loaded class is compatible with the serialized data.

  • How it works:

    • ObjectOutputStream.writeObject() writes the graph; readObject() reconstructs it without calling the constructor.

    • transient fields are skipped; static fields aren't part of instance state.

  • Role of serialVersionUID:

    • On deserialization the stored ID must match the current class's ID, else InvalidClassException.

    • If you omit it, the compiler auto-generates one from the class structure: any field/method change alters it and breaks old data.

    • Declare it explicitly (private static final long serialVersionUID) to control versioning intentionally.

java

public class User implements Serializable { private static final long serialVersionUID = 1L; private String name; private transient String password; // not serialized }

Q108.
What are 'Annotations' and how are they processed at runtime vs. compile time?

Mid

Annotations are metadata attached to code (classes, methods, fields, parameters) that don't change behavior by themselves: something must read and act on them. When that happens depends on the annotation's retention policy, which can be source-only, compile-time/bytecode, or runtime.

  • Retention controls availability (@Retention):

    • SOURCE: discarded after compilation (e.g. @Override, @SuppressWarnings).

    • CLASS: kept in the .class file but not loaded at runtime (the default).

    • RUNTIME: retained and readable via reflection.

  • Compile-time processing:

    • Annotation processors (javax.annotation.processing) run during javac to validate code or generate sources (Lombok, Dagger, MapStruct).

    • No runtime cost: errors caught early.

  • Runtime processing: Frameworks read RUNTIME annotations via reflection (getAnnotation()) to wire behavior: Spring @Autowired, JPA @Entity, JUnit @Test.

Q109.
Explain the 'Strong vs. Weak vs. Soft' reference types. When would you use a WeakHashMap?

Mid

Strong, soft, and weak references differ in how easily the GC may reclaim the referent: strong is never collected, soft is collected only under memory pressure, and weak is collected at the next GC once no strong reference remains. A WeakHashMap applies weak references to its keys so entries vanish automatically when the key is no longer referenced elsewhere.

  • Strong: Ordinary reference; keeps the object alive and is the source of most leaks if held too long.

  • Soft (SoftReference): Survives until the heap is nearly exhausted, then cleared before OutOfMemoryError; good for caches you want to keep as long as RAM allows.

  • Weak (WeakReference): Cleared eagerly at the next GC when only weakly reachable; good for associating data with an object without prolonging its life.

  • When to use WeakHashMap:

    • When the map should not be the thing that keeps a key alive: entries auto-remove once the key is garbage-collected.

    • Classic use: caches or metadata keyed by an object's identity (e.g. attaching extra info to objects you don't own), avoiding manual cleanup.

    • Caveat: only the key is weak, the value is strong; if the value strongly references the key the entry never clears.

    • Entry removal is non-deterministic (depends on GC timing), so don't rely on exact size().

java

Map<Key, Value> cache = new WeakHashMap<>(); Key k = new Key(); cache.put(k, computeValue()); // while k is strongly referenced, the entry stays k = null; // drop the only strong reference // after a GC, the entry becomes eligible for automatic removal

Q110.
How does a HashMap handle collisions in Java 8+? At what point does a linked list convert into a Red-Black Tree?

Senior

In Java 8+, a HashMap resolves collisions by chaining entries in the same bucket, and once a bucket grows too long it converts that chain from a linked list into a Red-Black Tree to improve lookup from O(n) to O(log n).

  • Collision handling: Keys hashing to the same bucket index are stored as nodes; the map walks them comparing with hashCode() then equals().

  • Treeification thresholds:

    1. A bucket converts to a tree when its chain reaches TREEIFY_THRESHOLD (8) entries,

    2. AND the table capacity is at least MIN_TREEIFY_CAPACITY (64); otherwise it just resizes the table instead.

  • Untreeify: On removal/resize, a tree bucket shrinks back to a list when it drops to UNTREEIFY_THRESHOLD (6).

  • Why a tree: it bounds worst-case collision cost (e.g. malicious or poor hash distributions) to O(log n), mitigating hash-collision DoS attacks.

Q111.
How does a HashMap work internally in Java 8? Explain the transition from LinkedList to TreeNode.

Senior

A HashMap stores entries in an array of buckets indexed by the key's hash; entries colliding in one bucket are chained, and Java 8 upgrades long chains to balanced trees for faster lookup.

  • Bucket placement: Index is computed from the key's hash, spread by (h = key.hashCode()) ^ (h >>> 16) then masked with (n - 1) so high bits influence the slot.

  • LinkedList to TreeNode transition:

    1. Colliding entries start as a singly-linked chain of Node objects.

    2. When a bucket's length reaches 8 and table capacity is ≥ 64, the chain is treeified into TreeNode objects forming a Red-Black Tree (O(log n) lookup).

    3. If capacity is below 64, the map resizes instead of treeifying.

    4. A tree reverts to a list when its size falls to 6.

  • Resizing: At size > capacity * loadFactor (default 0.75) the table doubles and entries are rehashed/split.

Q112.
In what specific scenarios would a LinkedList actually outperform an ArrayList, considering modern CPU cache behavior?

Senior

LinkedList wins only when you do frequent inserts/removals at the ends (or via an already-positioned iterator) and rarely random-access, since modern CPUs heavily favor the contiguous memory of ArrayList.

  • Queue/Deque workloads: Constant-time addFirst()/removeFirst() make it a natural FIFO queue; ArrayList front removal is O(n) due to shifting.

  • Mid-list edits during iteration: Removing/inserting via a ListIterator already at the spot is O(1) (relink nodes), versus O(n) array shifting.

  • The cache caveat: Each node is a separate heap object, so traversal causes cache misses and pointer chasing; for plain iteration or random access ArrayList usually wins even where Big-O looks equal.

  • Bottom line: In practice ArrayDeque often beats LinkedList for queue/stack needs too, so true wins are narrow.

Q113.
How does ConcurrentHashMap achieve thread safety, and how did its locking strategy change from segment locking to bucket-level CAS in Java 8?

Senior

ConcurrentHashMap allows concurrent reads with no locking and localizes write contention to individual buckets; Java 8 replaced the older fixed segment locks with fine-grained per-bucket synchronization plus CAS, greatly improving concurrency.

  • Pre-Java 8: segment locking: The map was split into a fixed number of segments (default 16), each a separately locked sub-table; concurrency was capped at the segment count.

  • Java 8: bucket-level CAS + synchronized:

    • Segments were dropped; inserting into an empty bucket uses a lock-free CAS on the bin head.

    • When a bucket already has entries, it locks only that bucket's first node with synchronized, so unrelated buckets proceed in parallel.

  • Reads are lock-free: Nodes use volatile fields for visibility, so get() never locks.

  • Other guarantees: Treeifies long buckets like HashMap, forbids null keys/values, and provides weakly-consistent (fail-safe) iterators.

Q114.
What is the difference between ClassNotFoundException and NoClassDefFoundError?

Senior

Both signal that a class can't be loaded, but ClassNotFoundException is a checked exception thrown during explicit dynamic loading, while NoClassDefFoundError is an Error thrown by the JVM when a class present at compile time is missing at runtime.

  • ClassNotFoundException:

    • A checked Exception thrown when code asks the loader for a class by name and it isn't found.

    • Triggered by Class.forName(), ClassLoader.loadClass(), etc.

  • NoClassDefFoundError:

    • An Error (unchecked) thrown when the class compiled fine but is absent from the classpath at runtime.

    • Also thrown if a class's static initializer previously failed, leaving it unusable.

  • Rule of thumb:

    • Exception = you tried to load it dynamically and it wasn't there.

    • Error = the JVM expected it (a normal reference) and couldn't link it.

Q115.
What are the risks of using parallelStream(), and how does it interact with the common ForkJoinPool?

Senior

parallelStream() splits work across multiple threads to use more cores, but it adds overhead and correctness risks, and by default all parallel streams in the JVM share one ForkJoinPool.commonPool(), so they compete for the same threads.

  • Correctness risks:

    • Shared mutable state or non-thread-safe collectors cause race conditions; lambdas must be stateless and side-effect-free.

    • Operations that depend on encounter order (forEachOrdered, limit) may behave differently or lose performance.

  • Performance risks:

    • Splitting, thread coordination, and merging add overhead; small datasets often run slower than sequential.

    • Sources that split poorly (LinkedList, iterator-based) gain little; ArrayList and arrays split well.

  • The shared common pool:

    • Default size is availableProcessors() - 1, shared across the whole JVM.

    • A blocking call (I/O, locks) inside a parallel stream ties up common-pool threads and can starve other parallel tasks application-wide.

    • To isolate work, submit the stream inside your own ForkJoinPool so it doesn't run on the common pool.

  • Rule of thumb: use it only for large, CPU-bound, easily-split, independent workloads, and measure.

Q116.
When is it actually detrimental to use .parallelStream(), and how does the underlying ForkJoinPool affect the performance of other parts of the application?

Senior

Parallel streams are detrimental when the dataset is small, the per-element work is cheap, the source splits poorly, or the operation isn't truly stateless: the splitting/merging overhead and thread coordination then cost more than they save. They also share the JVM-wide common ForkJoinPool, so a long parallel task can starve unrelated parts of the app.

  • When parallelism hurts:

    1. Small collections: fork/join setup dominates.

    2. Poorly splittable sources like LinkedList or stream from an iterator (vs ArrayList/arrays which split evenly).

    3. Operations with shared mutable state, ordering requirements, or blocking I/O inside the lambda.

    4. Cheap per-element work where memory bandwidth, not CPU, is the limit.

  • The shared ForkJoinPool problem:

    • By default all parallel streams use ForkJoinPool.commonPool(), sized to CPU cores minus one.

    • A blocking or long-running parallel stream occupies those threads, so other parallel streams (or anything using the common pool) queue up and stall.

    • Workaround: run the pipeline inside your own ForkJoinPool via submit, or avoid parallel streams for blocking work.

  • Rule of thumb: Parallelize only large, CPU-bound, stateless, easily-splittable workloads, and measure before trusting it.

Q117.
What is the 'Closed World Assumption' introduced by Sealed Classes, and why is it useful for the compiler?

Senior

The Closed World Assumption means a sealed type declares the complete, finite set of subtypes that may extend it, so the compiler knows every possible implementation at compile time.

  • "Closed" set of subtypes: A sealed type's permits clause lists exactly which classes/interfaces may extend it, no others allowed.

  • Enables exhaustiveness checking:

    • In a switch over a sealed type, if every permitted subtype is handled, no default branch is required and the compiler proves all cases are covered.

    • Add a new subtype later and the switch fails to compile until you handle it: errors caught at compile time, not runtime.

  • Contrast with the open world: A normal (non-sealed) class can be extended by anyone, so the compiler must assume unknown subtypes exist and always demands a default.

Q118.
What is the 'Algebraic Data Type' (ADT) pattern in Java, and how do Sealed Classes and Records work together to implement it?

Senior

An Algebraic Data Type models data as a fixed set of alternatives (a "sum" of types), where each alternative holds a fixed set of fields (a "product" of values). In Java, sealed types express the closed set of alternatives and records express each alternative's data, giving you a type-safe, exhaustively-checkable model.

  • Sum types (the "or"): A sealed interface or sealed class lists its permitted subtypes, so the value is exactly one of them.

  • Product types (the "and"): Each record bundles a fixed group of fields that travel together.

  • How they combine:

    • Records implements the sealed interface, forming the closed family of cases.

    • Consumers use switch with record/type patterns to deconstruct each case; the compiler proves all cases are handled.

  • Why it matters: You move behavior out of the data (no scattered polymorphic methods) and centralize it in exhaustive switches: adding a case forces every switch to be updated.

java

sealed interface Shape permits Circle, Rectangle {} record Circle(double radius) implements Shape {} record Rectangle(double w, double h) implements Shape {} double area(Shape s) { return switch (s) { case Circle c -> Math.PI * c.radius() * c.radius(); case Rectangle r -> r.w() * r.h(); }; // exhaustive: no default needed }

Q119.
What is the architectural benefit of using sealed classes and interfaces, and how do they improve the reliability of switch pattern matching?

Senior

Sealed types let an author declare a closed, known set of permitted implementations, turning an open hierarchy into a finite one the compiler can reason about. That closure is what makes switch pattern matching exhaustive and therefore reliable.

  • Architectural benefits:

    • Controlled extension: permits names exactly which types may extend/implement, documenting and enforcing the design.

    • Models a finite domain (the ADT "sum" of cases) so the type system mirrors the problem.

    • Stronger encapsulation of a hierarchy than public + convention without going fully final.

  • Reliability for switch:

    • The compiler knows every possible subtype, so it can prove a switch is exhaustive without a catch-all default.

    • Adding a new permitted type causes existing switches to fail compilation until updated: errors surface at build time, not runtime.

    • Avoiding a defensive default means genuinely unhandled cases are caught rather than silently swallowed.

Q120.
Explain the Java Memory Model (JMM) and the 'happens-before' relationship.

Senior

The Java Memory Model defines the rules for how and when writes by one thread become visible to others, and what reorderings the compiler/CPU may perform. "Happens-before" is the core ordering relation: if action A happens-before action B, then A's effects are guaranteed visible to and ordered before B.

  • Why the JMM exists:

    • Compilers, CPUs, and caches reorder and buffer memory operations for speed, so without rules a thread might never see another's updates (visibility) or see them out of order (ordering).

    • The JMM is the contract that says which behaviors are guaranteed versus undefined (a data race).

  • Happens-before guarantees:

    • Program order: actions in a single thread happen-before later actions in that same thread.

    • Monitor lock: unlocking a synchronized block happens-before a subsequent lock of the same monitor.

    • Volatile: a write to a volatile field happens-before every later read of that field.

    • Thread start/join: Thread.start() happens-before the thread's run; the thread's actions happen-before a successful join().

    • Transitivity: if A happens-before B and B happens-before C, then A happens-before C.

  • Data races:

    • Two accesses to the same non-final field, at least one a write, with no happens-before relation, is a race: results are unpredictable.

    • Use synchronized, volatile, final, or java.util.concurrent tools to establish the needed ordering.

  • Key insight: correctness comes from establishing happens-before edges, not from how fast or in what wall-clock order threads appear to run.

Q121.
What is the 'happens-before' relationship in the Java Memory Model, and why is it critical for thread safety?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q122.
Explain the Java Memory Model (JMM). Why is it possible for a thread to see a partially initialized object?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q123.
What is 'False Sharing' in a multithreaded Java application, and how does the @Contended annotation address it?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q124.
Explain the 'happens-before' relationship. Why does volatile solve visibility issues but not atomicity issues?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q125.
When would you use StampedLock over ReentrantReadWriteLock, and what are the tradeoffs of optimistic reading?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q126.
How do atomic classes like AtomicInteger work, and what is Compare-And-Swap (CAS)?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q127.
How would you identify a memory leak in a Java application if the Heap usage is constantly growing?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q128.
What is 'Escape Analysis' and how does it allow the JVM to perform scalar replacement?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q129.
Why can an OutOfMemoryError occur even if the heap has plenty of free space?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q130.
What is the 'Double Brace Initialization' anti-pattern, and why does it cause memory leaks?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q131.
What is Metaspace, and how does its management of class metadata differ from the old PermGen model? Why does it cause OutOfMemoryError differently?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q132.
Walk me through what happens in memory when you call new ArrayList(). Where is the object header stored, and how does the JVM track its age for GC?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q133.
Why are primitives stored on the stack while objects are on the heap? How does 'Escape Analysis' allow the JVM to sometimes allocate objects on the stack?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q134.
Explain the difference between the G1 Garbage Collector and the ZGC (Z Garbage Collector).

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q135.
What is the difference between the G1 and ZGC garbage collectors, and when would you prefer one over the other for a low-latency application?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q136.
How does the ZGC (Z Garbage Collector) achieve sub-millisecond pause times even with terabyte-sized heaps?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q137.
What are the primary differences between the G1 Garbage Collector and the ZGC, and in what scenario would you choose ZGC over G1?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q138.
What is 'Type Erasure' in Java Generics? What are its limitations?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q139.
Explain the PECS (Producer Extends, Consumer Super) rule in Generics.

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q140.
What is Type Erasure in Java Generics? Why can't you use primitives as type parameters, and how does 'Project Valhalla' aim to solve this?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q141.
How does 'CompletableFuture' handle exception propagation in an asynchronous pipeline?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q142.
What is the 'Fork/Join' framework, and how does 'work-stealing' help in load balancing?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q143.
What is the difference between CountDownLatch, CyclicBarrier, and Semaphore, and when would you use each?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q144.
Explain the concept of 'Thread Pinning' in the context of Virtual Threads. When does it happen?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q145.
Why can't you use 'synchronized' blocks effectively with Virtual Threads in certain scenarios?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q146.
When would you choose Virtual Threads over a reactive programming model (like CompletableFuture or Flux)?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q147.
Explain the concept of 'Carrier Thread Pinning.' In what scenarios does a virtual thread fail to unmount from its carrier?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q148.
Why would you choose Scoped Values over ThreadLocal in a system using millions of virtual threads?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q149.
What is 'Structured Concurrency' and how does it prevent thread leaks compared to the traditional ExecutorService?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q150.
Explain the concept of 'mounting' and 'unmounting' a virtual thread. What happens to the carrier thread when a virtual thread performs a blocking I/O operation?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q151.
What is 'thread pinning' in the context of Virtual Threads, and why does using the synchronized keyword potentially cause performance issues in a virtual thread environment?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q152.
How does Structured Concurrency improve the observability and reliability of multi-threaded tasks compared to using ExecutorService?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q153.
Why were Scoped Values introduced in Java 21, and what are the memory and scalability tradeoffs compared to using ThreadLocal?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q154.
How does the JIT (Just-In-Time) compiler decide when to compile a method into native code?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q155.
Explain the role of the JIT compiler. How does it optimize code at runtime compared to the initial bytecode interpretation?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q156.
What is 'Class Data Sharing' (CDS) and how does it improve the startup time of Java microservices in containers?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q157.
How does the JIT compiler decide when to move code from C1 to C2 (Tiered Compilation)?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q158.
Explain how the JIT compiler decides to move code from Level 1 to Level 4 (C2) compilation. What is 'code cache' exhaustion?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q159.
What is the Java Platform Module System (JPMS) introduced in Java 9, and what problems does it solve?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q160.
Why is standard Java Serialization often considered a security risk, and what are the modern alternatives for object persistence?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q161.
What is a 'ThreadLocal' variable, and what is the risk of using it in a thread-pooled environment?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q162.
Explain the difference between 'Strong', 'Soft', 'Weak', and 'Phantom' references.

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.