[{"data":1,"prerenderedAt":3854},["ShallowReactive",2],{"hub-java":3},{"framework":4,"topics":15,"qa":95},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Fjava.yml","Java interview questions on language fundamentals, object-oriented design, the Collections Framework, exception handling and concurrency — a staple of backend and enterprise technical interviews.","yml","java",{},"Java",5,"frameworks\u002Fjava",1,"jcUKEcQDoMZrreMRtZYJIVpkQlB-varlzbuwmzLr7kc",[16,24,33,42,51,59,68,77,86],{"id":17,"description":18,"extension":7,"frameworkSlug":8,"meta":19,"name":20,"order":13,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Fjava-fundamentals.yml","Primitives and wrappers, the String pool, pass-by-value semantics and the object model — the language basics every Java interview starts with.",{},"Fundamentals","fundamentals","topics\u002Fjava-fundamentals","I9Cp0oY-rFDDQ4-iChg29zHL5qVFZP30ULk-xU61i5Y",{"id":25,"description":26,"extension":7,"frameworkSlug":8,"meta":27,"name":28,"order":29,"slug":30,"stem":31,"__hash__":32},"topics\u002Ftopics\u002Fjava-oop.yml","Classes and objects, inheritance and polymorphism, interfaces vs abstract classes and the equals\u002FhashCode contract — the object model at the heart of every Java interview.",{},"Object-Oriented Programming",2,"oop","topics\u002Fjava-oop","A3ws_0D67Mc9WOPXPIFDm0mmP-46QC-BxugfwNhTWYI",{"id":34,"description":35,"extension":7,"frameworkSlug":8,"meta":36,"name":37,"order":38,"slug":39,"stem":40,"__hash__":41},"topics\u002Ftopics\u002Fjava-generics.yml","Type parameters, bounded types and wildcards (PECS) and the type erasure that underpins them — compile-time type safety for collections and APIs.",{},"Generics",3,"generics","topics\u002Fjava-generics","qD4bQH3YcT6lfgzLIroLr3wiNOaT1XQorSE8mv7sZWQ",{"id":43,"description":44,"extension":7,"frameworkSlug":8,"meta":45,"name":46,"order":47,"slug":48,"stem":49,"__hash__":50},"topics\u002Ftopics\u002Fjava-collections.yml","Lists, Sets and Maps, their implementations and trade-offs, iteration and ordering — the Collections Framework that powers most Java code.",{},"Collections",4,"collections","topics\u002Fjava-collections","Qhg8dbx8PBbzBhS3lAsIdG8j8Kxn7KWWybgZ4EaW-Fo",{"id":52,"description":53,"extension":7,"frameworkSlug":8,"meta":54,"name":55,"order":11,"slug":56,"stem":57,"__hash__":58},"topics\u002Ftopics\u002Fjava-streams-functional.yml","Lambdas and functional interfaces, the Stream API, Collectors and Optional — the functional style introduced in Java 8 that modern code is written in.",{},"Streams & Functional","streams-functional","topics\u002Fjava-streams-functional","XJnlj_VnEt2efDoTmd60uimYkqFZ3OtlhypVsp5vR58",{"id":60,"description":61,"extension":7,"frameworkSlug":8,"meta":62,"name":63,"order":64,"slug":65,"stem":66,"__hash__":67},"topics\u002Ftopics\u002Fjava-exceptions.yml","Checked vs unchecked exceptions, try\u002Fcatch\u002Ffinally, try-with-resources and designing robust error handling in Java.",{},"Exceptions",6,"exceptions","topics\u002Fjava-exceptions","-Max1ZDkqpkyJ3ydt09X11BQpRsg0nddQrF2kCwuKf0",{"id":69,"description":70,"extension":7,"frameworkSlug":8,"meta":71,"name":72,"order":73,"slug":74,"stem":75,"__hash__":76},"topics\u002Ftopics\u002Fjava-concurrency.yml","Threads, synchronization, the memory model, executors and the high-level concurrency utilities used to write correct multithreaded Java.",{},"Concurrency",7,"concurrency","topics\u002Fjava-concurrency","0jJ0DFbypDaHzVDGSVoXiAFbJCsVljM3VSfiLMmplTg",{"id":78,"description":79,"extension":7,"frameworkSlug":8,"meta":80,"name":81,"order":82,"slug":83,"stem":84,"__hash__":85},"topics\u002Ftopics\u002Fjava-jvm-internals.yml","The heap and stack, garbage collection and class loading — how the Java Virtual Machine runs, manages memory and loads your code.",{},"JVM Internals",8,"jvm-internals","topics\u002Fjava-jvm-internals","3xsvKXS7o9kBEe5kuidQ3YxF-l6nDxs-vn1LZ3oXvoY",{"id":87,"description":88,"extension":7,"frameworkSlug":8,"meta":89,"name":90,"order":91,"slug":92,"stem":93,"__hash__":94},"topics\u002Ftopics\u002Fjava-modern-java.yml","Records, sealed classes and pattern matching for switch — the language features from Java 14+ that make recent Java more concise and expressive.",{},"Modern Java",9,"modern-java","topics\u002Fjava-modern-java","39pOVSqSYZr8fjGosC8uuiD9QnIqHf40JmGYx0V6has",[96,257,413,560,707,811,910,985,1070,1169,1270,1376,1472,1576,1675,1769,1840,1919,2018,2120,2218,2314,2423,2519,2594,2664,2738,2841,2938,3029,3123,3186,3259,3350,3441,3533,3596,3670,3737,3796],{"id":97,"title":98,"body":99,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":107,"navigation":108,"order":13,"path":109,"questions":110,"questionsCount":249,"related":250,"seo":251,"seoDescription":252,"stem":253,"subtopic":254,"topic":46,"topicSlug":48,"updated":255,"__hash__":256},"qa\u002Fjava\u002Fcollections\u002Flist-map-set.md","List Map Set",{"type":100,"value":101,"toc":102},"minimark",[],{"title":103,"searchDepth":29,"depth":29,"links":104},"",[],"medium","md",{},true,"\u002Fjava\u002Fcollections\u002Flist-map-set",[111,116,120,124,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,193,197,201,205,209,213,217,221,225,229,233,237,241,245],{"id":112,"difficulty":113,"q":114,"a":115},"collection-hierarchy","easy","What is the Java Collections Framework?","A unified set of interfaces and implementations for storing groups of objects.\nThe root is `Iterable` -> `Collection`, which branches into:\n\n- **`List`** — ordered, indexed, allows duplicates (`ArrayList`, `LinkedList`).\n- **`Set`** — no duplicates (`HashSet`, `TreeSet`, `LinkedHashSet`).\n- **`Queue`\u002F`Deque`** — ordering for processing (`ArrayDeque`, `PriorityQueue`).\n\n**`Map`** is part of the framework but **not** a `Collection` (it stores\nkey->value pairs, not single elements).\n\n```java\nList\u003CString> list = new ArrayList\u003C>();\nSet\u003CString> set   = new HashSet\u003C>();\nMap\u003CString, Integer> map = new HashMap\u003C>();\n```\n\nProgramming to the interface (`List` not `ArrayList`) lets you swap\nimplementations freely.\n",{"id":117,"difficulty":113,"q":118,"a":119},"list-vs-set-vs-map","What is the difference between List, Set and Map?","- **`List`** — an **ordered, indexed** sequence that **allows duplicates**.\n  Access by position.\n- **`Set`** — an **unordered** collection of **unique** elements (uniqueness\n  defined by `equals`\u002F`hashCode`).\n- **`Map`** — **key->value** pairs with **unique keys**; not a `Collection`.\n\n```java\nList.of(\"a\", \"a\", \"b\");          \u002F\u002F [a, a, b] — duplicates kept\nSet.of(\"a\", \"a\", \"b\");           \u002F\u002F throws — duplicate in Set.of\nnew HashSet\u003C>(List.of(\"a\",\"a\")); \u002F\u002F {a} — duplicate dropped\nMap.of(\"k1\", 1, \"k2\", 2);        \u002F\u002F {k1=1, k2=2}\n```\n\nPick by need: ordered\u002Findexed -> List; uniqueness\u002Fmembership -> Set; lookups by\nkey -> Map.\n",{"id":121,"difficulty":105,"q":122,"a":123},"arraylist-vs-linkedlist","What is the difference between ArrayList and LinkedList?","- **`ArrayList`** — backed by a **resizable array**. O(1) random access by\n  index; O(1) amortized append; O(n) insert\u002Fremove in the middle (shifting).\n  Cache-friendly, lower memory overhead.\n- **`LinkedList`** — a **doubly-linked list**. O(1) insert\u002Fremove at the ends\n  (or at a known node); but O(n) index access (must walk the chain) and higher\n  per-element memory (node pointers).\n\n```java\nList\u003CInteger> a = new ArrayList\u003C>();\na.get(1000);          \u002F\u002F O(1)\nList\u003CInteger> l = new LinkedList\u003C>();\nl.get(1000);          \u002F\u002F O(n) — walks 1000 nodes\n```\n\nIn practice **`ArrayList` wins almost always** — its cache locality beats\n`LinkedList` even for many insert\u002Fremove patterns. Use `LinkedList` mainly as a\n`Deque`\u002Fqueue.\n",{"id":125,"difficulty":126,"q":127,"a":128},"hashmap-internals","hard","How does HashMap work internally?","A `HashMap` is an **array of buckets**. To store a key it computes\n`hashCode()`, spreads the bits, and maps it to a bucket index. Collisions (keys\nlanding in the same bucket) are chained in a **linked list**, which **converts\nto a balanced tree (red-black)** once a bucket exceeds 8 entries (and the table\nis ≥64) — keeping worst-case lookups at O(log n) instead of O(n).\n\n```java\nMap\u003CString, Integer> m = new HashMap\u003C>();\nm.put(\"a\", 1);   \u002F\u002F hash(\"a\") -> bucket -> store entry\nm.get(\"a\");      \u002F\u002F hash(\"a\") -> bucket -> equals() scan -> 1\n```\n\nLookup\u002Finsert are **O(1) average**. When the size exceeds `capacity *\nloadFactor` (default 16 * 0.75 = 12), the table **resizes** (doubles) and\nrehashes. This is why a correct `hashCode`\u002F`equals` pair is essential.\n",{"id":130,"difficulty":126,"q":131,"a":132},"load-factor","What are capacity and load factor in a HashMap?","- **Capacity** — the number of buckets (always a power of two, default 16).\n- **Load factor** — the fullness threshold (default 0.75). When\n  `size > capacity * loadFactor`, the map **resizes** (capacity doubles) and\n  rehashes all entries.\n\n```java\n\u002F\u002F pre-size when you know roughly how many entries to avoid resizes\nMap\u003CString,Integer> m = new HashMap\u003C>(64);\n```\n\nThe 0.75 default trades space vs time: lower load factor = fewer collisions but\nmore memory; higher = denser but slower lookups. Pre-sizing a known-large map\navoids repeated O(n) resizes during population.\n",{"id":134,"difficulty":105,"q":135,"a":136},"hashmap-vs-hashtable","What is the difference between HashMap, Hashtable and ConcurrentHashMap?","- **`HashMap`** — not synchronized, allows **one `null` key** and `null`\n  values, fastest. Use single-threaded or with external synchronization.\n- **`Hashtable`** — legacy, **fully synchronized** (every method locks the whole\n  table), **no `null`** keys\u002Fvalues. Largely obsolete.\n- **`ConcurrentHashMap`** — thread-safe with **fine-grained locking** (per-bin\n  CAS, not a global lock), no `null` keys\u002Fvalues, high concurrency.\n\n```java\nMap\u003CString,Integer> safe = new ConcurrentHashMap\u003C>(); \u002F\u002F modern thread-safe choice\n```\n\nFor concurrent code, prefer **`ConcurrentHashMap`** over `Hashtable` or\n`Collections.synchronizedMap` — it scales far better under contention.\n",{"id":138,"difficulty":105,"q":139,"a":140},"hashset-treeset-linkedhashset","What is the difference between HashSet, LinkedHashSet and TreeSet?","- **`HashSet`** — backed by a `HashMap`; **no ordering**, O(1) add\u002Fcontains.\n- **`LinkedHashSet`** — `HashSet` + a linked list, so it preserves\n  **insertion order**; O(1) with slightly more memory.\n- **`TreeSet`** — a red-black tree; keeps elements in **sorted order**, O(log n)\n  operations, requires `Comparable`\u002F`Comparator`.\n\n```java\nnew HashSet\u003C>(List.of(3,1,2));       \u002F\u002F order undefined, e.g. [1,2,3] or other\nnew LinkedHashSet\u003C>(List.of(3,1,2)); \u002F\u002F [3, 1, 2] — insertion order\nnew TreeSet\u003C>(List.of(3,1,2));       \u002F\u002F [1, 2, 3] — sorted\n```\n\nChoose by requirement: speed -> HashSet; remember order -> LinkedHashSet; sorted\u002F\nrange queries -> TreeSet.\n",{"id":142,"difficulty":105,"q":143,"a":144},"hashmap-treemap-linkedhashmap","How do HashMap, LinkedHashMap and TreeMap differ?","They mirror the Set variants:\n\n- **`HashMap`** — no order, O(1) average.\n- **`LinkedHashMap`** — insertion order (or access order, enabling easy LRU\n  caches), O(1).\n- **`TreeMap`** — keys sorted, O(log n), supports range\u002Fnavigation methods\n  (`firstKey`, `ceilingKey`, `subMap`).\n\n```java\n\u002F\u002F LinkedHashMap as an LRU cache\nvar lru = new LinkedHashMap\u003CString,Integer>(16, 0.75f, true) {\n  protected boolean removeEldestEntry(Map.Entry\u003CString,Integer> e) {\n    return size() > 100;\n  }\n};\n```\n\n`TreeMap`'s navigation API is its superpower; `LinkedHashMap`'s access-order\nmode is the classic LRU trick.\n",{"id":146,"difficulty":126,"q":147,"a":148},"fail-fast","What is a fail-fast iterator and ConcurrentModificationException?","Most collection iterators are **fail-fast**: they track a `modCount`, and if the\ncollection is structurally modified during iteration (other than through the\niterator's own `remove`), they throw **`ConcurrentModificationException`** —\nfailing immediately rather than risking corrupt results.\n\n```java\nfor (String s : list) {\n  if (s.isEmpty()) list.remove(s); \u002F\u002F ConcurrentModificationException\n}\n\nIterator\u003CString> it = list.iterator();\nwhile (it.hasNext()) {\n  if (it.next().isEmpty()) it.remove(); \u002F\u002F safe via the iterator\n}\nlist.removeIf(String::isEmpty);          \u002F\u002F cleanest\n```\n\nFail-fast is **best-effort** (not guaranteed). Concurrent collections like\n`CopyOnWriteArrayList`\u002F`ConcurrentHashMap` are **fail-safe** instead — they\niterate over a snapshot and don't throw.\n",{"id":150,"difficulty":105,"q":151,"a":152},"comparable-vs-comparator","What is the difference between Comparable and Comparator?","- **`Comparable\u003CT>`** — the type's **natural ordering**, implemented *by the\n  class itself* via `compareTo`. One ordering per class.\n- **`Comparator\u003CT>`** — an **external** ordering object via `compare`, so you can\n  define many orderings without touching the class.\n\n```java\nclass User implements Comparable\u003CUser> {\n  int age; String name;\n  public int compareTo(User o) { return Integer.compare(age, o.age); } \u002F\u002F natural\n}\n\u002F\u002F alternate orderings without modifying User:\nusers.sort(Comparator.comparing(u -> u.name));\nusers.sort(Comparator.comparingInt((User u) -> u.age).reversed()\n                     .thenComparing(u -> u.name));\n```\n\nRule of thumb: one obvious default ordering -> `Comparable`; multiple\u002Fcontextual\norderings -> `Comparator` (which also composes nicely with `thenComparing`).\n",{"id":154,"difficulty":105,"q":155,"a":156},"iterator-vs-listiterator","What is the difference between Iterator and ListIterator?","- **`Iterator`** — forward-only traversal of any `Collection`; supports\n  `hasNext`, `next`, and `remove`.\n- **`ListIterator`** — a `List`-only iterator that goes **both directions**\n  (`hasPrevious`\u002F`previous`), exposes indices (`nextIndex`), and can **`add`**\n  and **`set`** elements during iteration.\n\n```java\nListIterator\u003CString> it = list.listIterator();\nwhile (it.hasNext()) {\n  String s = it.next();\n  if (s.isBlank()) it.set(\"(empty)\"); \u002F\u002F replace in place\n}\n```\n\nUse `ListIterator` when you need to walk backward or modify elements while\niterating a list.\n",{"id":158,"difficulty":105,"q":159,"a":160},"arraylist-resize","How does ArrayList grow, and what is amortized O(1)?","An `ArrayList` holds an internal array. When it fills up, it allocates a **larger\narray** (~1.5×) and copies the elements over — an O(n) operation. But because\ngrowth happens **rarely** (geometrically), the *average* cost of `add` over many\ncalls is **O(1) amortized**.\n\n```java\nList\u003CInteger> list = new ArrayList\u003C>(1000); \u002F\u002F pre-size: skip the resizes\nfor (int i = 0; i \u003C 1000; i++) list.add(i);\n```\n\nIf you know the final size, pass an **initial capacity** to avoid the repeated\ncopies. Note `size()` (number of elements) differs from the internal capacity.\n",{"id":162,"difficulty":113,"q":163,"a":164},"generics-why","Why are generics used in collections?","Generics give collections **compile-time type safety** and remove casts. Before\ngenerics, collections held `Object`, so you could insert anything and had to cast\non the way out — risking `ClassCastException` at runtime.\n\n```java\nList\u003CString> names = new ArrayList\u003C>();\nnames.add(\"Ada\");\nString s = names.get(0);   \u002F\u002F no cast; adding an Integer won't compile\n\nList raw = new ArrayList(); \u002F\u002F raw type — unsafe, avoid\nraw.add(42);\nString bad = (String) raw.get(0); \u002F\u002F compiles, ClassCastException at runtime\n```\n\nGenerics catch type errors at **compile time** and make code self-documenting.\n",{"id":166,"difficulty":126,"q":167,"a":168},"type-erasure","What is type erasure?","Java generics are a **compile-time** feature. After type checking, the compiler\n**erases** type parameters — `List\u003CString>` and `List\u003CInteger>` both become raw\n`List` at runtime, with casts inserted automatically. This keeps backward\ncompatibility with pre-generics code.\n\n```java\nList\u003CString> a = new ArrayList\u003C>();\nList\u003CInteger> b = new ArrayList\u003C>();\na.getClass() == b.getClass();  \u002F\u002F true — same runtime class\n\n\u002F\u002F consequences of erasure:\n\u002F\u002F new T[]      -> illegal\n\u002F\u002F x instanceof List\u003CString> -> illegal (only List\u003C?>)\n```\n\nErasure is why you can't do `new T()`, create generic arrays, or check a generic\ntype with `instanceof` — the type info simply isn't there at runtime.\n",{"id":170,"difficulty":126,"q":171,"a":172},"wildcards","What do the ? extends and ? super wildcards mean (PECS)?","Bounded wildcards control what you can read\u002Fwrite through a generic reference:\n\n- **`? extends T`** — an unknown subtype of T; you can **read** Ts out, but\n  **can't add** (the exact type is unknown). A **Producer**.\n- **`? super T`** — an unknown supertype of T; you can **add** Ts, but reads come\n  back as `Object`. A **Consumer**.\n\nThe mnemonic is **PECS — Producer `extends`, Consumer `super`**:\n\n```java\nvoid copy(List\u003C? extends Number> src, List\u003C? super Number> dst) {\n  for (Number n : src) dst.add(n); \u002F\u002F read from producer, write to consumer\n}\n```\n\n`src` produces values (read-only), `dst` consumes them (write-ok). This is how\n`Collections.copy` and friends are typed.\n",{"id":174,"difficulty":105,"q":175,"a":176},"queue-deque","What are Queue and Deque, and which implementations are common?","- **`Queue`** — FIFO processing; `offer`\u002F`poll`\u002F`peek`. `PriorityQueue` orders\n  by priority instead of arrival.\n- **`Deque`** (\"deck\") — double-ended queue; add\u002Fremove at **both ends**. Works\n  as a queue **or** a stack.\n\n```java\nDeque\u003CInteger> stack = new ArrayDeque\u003C>();\nstack.push(1); stack.push(2); stack.pop();  \u002F\u002F LIFO -> 2\n\nQueue\u003CInteger> q = new ArrayDeque\u003C>();\nq.offer(1); q.offer(2); q.poll();           \u002F\u002F FIFO -> 1\n\nQueue\u003CInteger> pq = new PriorityQueue\u003C>();\npq.offer(5); pq.offer(1); pq.peek();        \u002F\u002F 1 (smallest first)\n```\n\nPrefer **`ArrayDeque`** over the legacy `Stack` class (synchronized, extends\n`Vector`) for stack\u002Fqueue needs.\n",{"id":178,"difficulty":105,"q":179,"a":180},"immutable-collections","How do you create immutable collections?","- **`List.of` \u002F `Set.of` \u002F `Map.of`** (Java 9+) — concise, truly immutable,\n  reject `null` and (for Set\u002FMap) duplicates.\n- **`Collections.unmodifiableList(...)`** — an unmodifiable *view* over an\n  existing collection.\n- **`List.copyOf(...)`** — an immutable copy of any collection.\n\n```java\nList\u003CString> a = List.of(\"x\", \"y\");        \u002F\u002F immutable\na.add(\"z\");                                 \u002F\u002F UnsupportedOperationException\n\nList\u003CString> backing = new ArrayList\u003C>(List.of(\"x\"));\nList\u003CString> view = Collections.unmodifiableList(backing);\nbacking.add(\"y\");                           \u002F\u002F view reflects this — it's a VIEW\n```\n\nGotcha: `unmodifiableList` is a **view** — mutating the backing list still shows\nthrough it. `List.of`\u002F`copyOf` are genuinely independent and immutable.\n",{"id":182,"difficulty":105,"q":183,"a":184},"null-handling","Which collections allow null and which do not?","- **`HashMap`** — one `null` key, many `null` values. **`HashSet`** — one\n  `null` element. `ArrayList`\u002F`LinkedList` allow `null`s.\n- **`Hashtable`, `ConcurrentHashMap`, `TreeMap` (keys)** — **no `null`** (TreeMap\n  can't compare null; concurrent maps disallow it to avoid ambiguity).\n- **`List.of`\u002F`Set.of`\u002F`Map.of`** — reject `null` entirely.\n\n```java\nnew HashMap\u003C>().put(null, 1);          \u002F\u002F\nnew ConcurrentHashMap\u003C>().put(null,1); \u002F\u002F NullPointerException\nList.of(\"a\", null);                    \u002F\u002F NullPointerException\n```\n\nAvoiding `null` (using `Optional` or sentinel objects) sidesteps a whole class\nof these errors.\n",{"id":186,"difficulty":113,"q":187,"a":188},"collections-utility","What does the Collections utility class provide?","`java.util.Collections` is a toolbox of static helpers that operate on\ncollections: `sort`, `reverse`, `shuffle`, `min`\u002F`max`, `binarySearch`,\n`frequency`, `unmodifiableXxx`, `synchronizedXxx`, and `emptyList()`\u002F\n`singletonList()`.\n\n```java\nList\u003CInteger> nums = new ArrayList\u003C>(List.of(3, 1, 2));\nCollections.sort(nums);                 \u002F\u002F [1, 2, 3]\nCollections.reverse(nums);              \u002F\u002F [3, 2, 1]\nint max = Collections.max(nums);        \u002F\u002F 3\n```\n\nDon't confuse `Collections` (utility class, plural) with `Collection` (the\ninterface). `Arrays` is its array-focused sibling (`Arrays.sort`,\n`Arrays.asList`).\n",{"id":190,"difficulty":126,"q":191,"a":192},"arrays-aslist","What are the pitfalls of Arrays.asList()?","`Arrays.asList` returns a **fixed-size list backed by the array** — not a normal\n`ArrayList`. You can `set` elements (it writes through to the array) but **can't\n`add`\u002F`remove`** (throws `UnsupportedOperationException`).\n\n```java\nList\u003CInteger> l = Arrays.asList(1, 2, 3);\nl.set(0, 9);   \u002F\u002F writes through to the backing array\nl.add(4);      \u002F\u002F UnsupportedOperationException\n\n\u002F\u002F also: a primitive array gives a 1-element List\u003Cint[]>, not List\u003CInteger>!\nList\u003Cint[]> oops = Arrays.asList(new int[]{1, 2, 3}); \u002F\u002F size 1\n\nList\u003CInteger> real = new ArrayList\u003C>(Arrays.asList(1, 2, 3)); \u002F\u002F mutable copy\n```\n\nWrap it in `new ArrayList\u003C>(...)` for a fully mutable list, and remember\nautoboxing: pass `Integer[]`, not `int[]`.\n",{"id":194,"difficulty":105,"q":195,"a":196},"set-uniqueness","How does a HashSet decide that two elements are duplicates?","A `HashSet` (backed by a `HashMap`) treats two elements as duplicates when their\n**`hashCode()` matches** *and* **`equals()` returns true**. So uniqueness depends\nentirely on a correct `equals`\u002F`hashCode` implementation.\n\n```java\nclass P { int x;\n  \u002F\u002F no equals\u002FhashCode -> identity-based, \"duplicates\" stay\n}\nSet\u003CP> s = new HashSet\u003C>();\ns.add(new P()); s.add(new P());  \u002F\u002F size 2 (different objects)\n```\n\nIf you forget to override them, two logically-equal objects are treated as\ndistinct. If you override `equals` but not `hashCode` (or vice versa), the set\nmay store duplicates or fail to find elements.\n",{"id":198,"difficulty":126,"q":199,"a":200},"mutable-key","What happens if you use a mutable object as a HashMap key?","The map places the key in a bucket based on its **hash at insertion time**. If\nyou then **mutate the key** so its `hashCode` changes, it ends up in the \"wrong\"\nbucket — the map can no longer find it, even with the same reference.\n\n```java\nMap\u003CList\u003CInteger>, String> m = new HashMap\u003C>();\nList\u003CInteger> key = new ArrayList\u003C>(List.of(1));\nm.put(key, \"v\");\nkey.add(2);                 \u002F\u002F mutates the key -> hashCode changes\nm.get(key);                 \u002F\u002F null! lost in the wrong bucket\n```\n\nRule: **use immutable keys** (`String`, `Integer`, records, frozen value\nobjects). It's the same reason Python forbids list keys.\n",{"id":202,"difficulty":105,"q":203,"a":204},"concurrent-modification-map","How do you safely remove entries from a Map while iterating?","Don't call `map.remove` inside an enhanced-for over its entries — that throws\n`ConcurrentModificationException`. Use the **iterator's `remove`**, or the\ncleaner `removeIf`\u002F`entrySet().removeIf`, or `keySet`\u002F`values` views.\n\n```java\n\u002F\u002F iterator\nIterator\u003CMap.Entry\u003CString,Integer>> it = map.entrySet().iterator();\nwhile (it.hasNext()) {\n  if (it.next().getValue() == 0) it.remove();\n}\n\u002F\u002F concise\nmap.values().removeIf(v -> v == 0);\nmap.entrySet().removeIf(e -> e.getValue() == 0);\n```\n\nFor concurrent access from multiple threads, use `ConcurrentHashMap`, whose\niterators are fail-safe.\n",{"id":206,"difficulty":105,"q":207,"a":208},"stack-vector","Why are Vector and Stack discouraged?","`Vector` and its subclass `Stack` are **legacy synchronized** collections from\nJava 1.0. Every method is synchronized, so they pay locking overhead even in\nsingle-threaded code, and that per-method locking doesn't make *compound*\noperations atomic anyway.\n\n```java\nDeque\u003CInteger> stack = new ArrayDeque\u003C>(); \u002F\u002F modern stack\nList\u003CInteger> list = new ArrayList\u003C>();    \u002F\u002F modern list\n```\n\nUse `ArrayList` (unsynchronized list), `ArrayDeque` (stack\u002Fqueue), and pick a\n*concurrent* collection or explicit synchronization when you genuinely need\nthread safety — not `Vector`\u002F`Stack`.\n",{"id":210,"difficulty":105,"q":211,"a":212},"map-getordefault-merge","What do getOrDefault, computeIfAbsent and merge do?","Java 8 added convenience methods that simplify common map idioms:\n\n- **`getOrDefault(k, d)`** — value for `k`, or `d` if absent.\n- **`computeIfAbsent(k, fn)`** — compute and store a value only if `k` is\n  missing; perfect for multimaps.\n- **`merge(k, v, fn)`** — combine an existing value with a new one; perfect for\n  counting.\n\n```java\n\u002F\u002F grouping (multimap)\nmap.computeIfAbsent(key, k -> new ArrayList\u003C>()).add(item);\n\n\u002F\u002F frequency count\ncounts.merge(word, 1, Integer::sum);\n\nint n = counts.getOrDefault(\"x\", 0);\n```\n\nThese replace verbose `if (map.containsKey(...)) ... else ...` blocks and are\natomic on `ConcurrentHashMap`.\n",{"id":214,"difficulty":105,"q":215,"a":216},"priorityqueue","How does a PriorityQueue work?","A `PriorityQueue` is a **binary heap** that always dequeues the **highest-\npriority** element (by natural order or a `Comparator`), not FIFO. `offer`\u002F`poll`\nare O(log n); `peek` is O(1).\n\n```java\n\u002F\u002F min-heap (default): smallest first\nQueue\u003CInteger> min = new PriorityQueue\u003C>();\n\u002F\u002F max-heap: reverse the comparator\nQueue\u003CInteger> max = new PriorityQueue\u003C>(Comparator.reverseOrder());\nmax.offer(1); max.offer(5); max.peek(); \u002F\u002F 5\n```\n\nCaveat: it's only ordered at the **head** — iterating it does *not* yield sorted\norder. It's the go-to for \"top-K\", Dijkstra, and scheduling problems.\n",{"id":218,"difficulty":105,"q":219,"a":220},"synchronized-collections","What is the difference between synchronized and concurrent collections?","- **`Collections.synchronizedList\u002FMap(...)`** — wraps a collection so each method\n  locks the **whole object**. Simple, but compound operations\n  (check-then-act, iteration) still need external synchronization, and there's\n  no concurrency.\n- **Concurrent collections** (`ConcurrentHashMap`, `CopyOnWriteArrayList`,\n  `ConcurrentLinkedQueue`) — designed for concurrency with fine-grained or\n  lock-free strategies; far better throughput.\n\n```java\nList\u003CInteger> s = Collections.synchronizedList(new ArrayList\u003C>());\nsynchronized (s) {                 \u002F\u002F still must lock to iterate safely\n  for (int x : s) { }\n}\nMap\u003CString,Integer> c = new ConcurrentHashMap\u003C>(); \u002F\u002F no external lock needed\n```\n\nPrefer the concurrent collections in new code.\n",{"id":222,"difficulty":126,"q":223,"a":224},"copyonwrite","When would you use CopyOnWriteArrayList?","`CopyOnWriteArrayList` makes a fresh copy of the backing array on **every\nmutation**, so reads and iteration are **lock-free and never throw\n`ConcurrentModificationException`** (iterators see a stable snapshot). The cost:\nwrites are O(n).\n\n```java\nList\u003CListener> listeners = new CopyOnWriteArrayList\u003C>();\nfor (Listener l : listeners) l.onEvent(); \u002F\u002F safe even if another thread adds\n```\n\nIdeal for **read-mostly, write-rarely** scenarios with concurrent iteration —\nclassically event-listener lists. Terrible for write-heavy workloads.\n",{"id":226,"difficulty":105,"q":227,"a":228},"equals-in-collections","Why must equals and hashCode be consistent for collections to work?","Hash-based collections (`HashMap`, `HashSet`) locate elements by **hash first,\nthen `equals`**. If two equal objects have different hash codes, they land in\ndifferent buckets and the collection can't recognize them as the same — you get\nduplicates in a Set or failed lookups in a Map.\n\n```java\nclass Key {\n  int id;\n  Key(int id) { this.id = id; }\n  @Override public boolean equals(Object o) {\n    return o instanceof Key k && k.id == id;\n  }\n  \u002F\u002F forgot hashCode -> equal Keys get different hashes\n}\nMap\u003CKey,String> m = new HashMap\u003C>();\nm.put(new Key(1), \"a\");\nm.get(new Key(1));   \u002F\u002F null — wrong bucket\n```\n\nAlways override **both together**, keeping them based on the same fields.\n",{"id":230,"difficulty":126,"q":231,"a":232},"tree-navigation","What navigation methods do TreeMap and TreeSet provide?","Because they're sorted, `TreeMap`\u002F`TreeSet` (the `NavigableMap`\u002F`NavigableSet`\ninterfaces) offer **range and neighbor queries** that hash structures can't:\n\n- `first()\u002Flast()`, `floor(x)` (≤ x), `ceiling(x)` (≥ x), `lower(x)` (\u003C x),\n  `higher(x)` (> x).\n- `headSet`, `tailSet`, `subSet` \u002F `headMap`, `tailMap`, `subMap` for ranges.\n\n```java\nNavigableSet\u003CInteger> s = new TreeSet\u003C>(List.of(10, 20, 30));\ns.floor(25);    \u002F\u002F 20  (largest ≤ 25)\ns.ceiling(25);  \u002F\u002F 30  (smallest ≥ 25)\ns.subSet(15, 35); \u002F\u002F [20, 30]\n```\n\nThese make `TreeMap`\u002F`TreeSet` the choice for \"nearest value\", ranges, and\nordered iteration — at O(log n) per operation.\n",{"id":234,"difficulty":105,"q":235,"a":236},"enumset-enummap","What are EnumSet and EnumMap and why use them?","Specialized, highly efficient collections for **enum** keys\u002Felements.\n`EnumSet` is internally a **bit vector**; `EnumMap` is backed by a **plain\narray** indexed by `ordinal()`. Both are much faster and smaller than\n`HashSet`\u002F`HashMap` for enums, and iterate in **enum declaration order**.\n\n```java\nenum Day { MON, TUE, WED, THU, FRI, SAT, SUN }\nEnumSet\u003CDay> weekend = EnumSet.of(Day.SAT, Day.SUN);\nEnumMap\u003CDay, String> plans = new EnumMap\u003C>(Day.class);\nplans.put(Day.MON, \"gym\");\n```\n\nWhenever your keys are enum constants, prefer these over the general-purpose\ncollections.\n",{"id":238,"difficulty":105,"q":239,"a":240},"stream-collectors","How do you build collections from a Stream?","Terminal `collect` with the `Collectors` factory turns a stream into a\ncollection or grouped structure:\n\n```java\nList\u003CString> upper = names.stream()\n    .map(String::toUpperCase)\n    .collect(Collectors.toList());        \u002F\u002F or .toList() (Java 16+)\n\nMap\u003CBoolean, List\u003CInteger>> parts = nums.stream()\n    .collect(Collectors.partitioningBy(n -> n % 2 == 0));\n\nMap\u003CDept, List\u003CEmp>> byDept = emps.stream()\n    .collect(Collectors.groupingBy(Emp::dept));\n```\n\n`Collectors` covers `toSet`, `toMap`, `groupingBy`, `partitioningBy`,\n`joining`, and `counting` — declarative replacements for manual loop-and-add.\n",{"id":242,"difficulty":126,"q":243,"a":244},"list-remove-int-trap","What is the trap with List.remove and an int argument?","`List` has two overloads: `remove(int index)` removes **by position**, and\n`remove(Object o)` removes **by value**. With a `List\u003CInteger>`, passing a\nprimitive `int` calls the **index** version — not the value one.\n\n```java\nList\u003CInteger> list = new ArrayList\u003C>(List.of(10, 20, 30));\nlist.remove(1);                 \u002F\u002F removes INDEX 1 -> [10, 30]\nlist.remove(Integer.valueOf(10)); \u002F\u002F removes the VALUE 10 -> [30]\n```\n\nTo remove a value, box it explicitly with `Integer.valueOf(x)` (or cast to\n`(Integer)`). This is one of the most common surprise bugs with integer lists.\n",{"id":246,"difficulty":113,"q":247,"a":248},"choosing-collection","How do you choose the right collection for a task?","Match the data structure to the dominant operation:\n\n- Ordered list, index access, mostly appends -> **`ArrayList`**.\n- Unique elements, fast membership tests -> **`HashSet`**.\n- Key->value lookups -> **`HashMap`**.\n- Need sorted order or range queries -> **`TreeMap`\u002F`TreeSet`**.\n- Preserve insertion order -> **`LinkedHashMap`\u002F`LinkedHashSet`**.\n- FIFO queue \u002F stack -> **`ArrayDeque`**; priority -> **`PriorityQueue`**.\n- Concurrent access -> **`ConcurrentHashMap`**, `CopyOnWriteArrayList`.\n\n```java\nMap\u003CString,Integer> wordCount = new HashMap\u003C>();   \u002F\u002F counting\nSet\u003CString> seen = new HashSet\u003C>();                \u002F\u002F dedupe\n```\n\nStart from the access pattern (lookup? order? uniqueness? concurrency?) and the\nchoice usually falls out.\n",34,null,{"description":103},"Java Collections Framework interview questions — List vs Set vs Map, ArrayList vs LinkedList, HashMap internals, fail-fast iterators, Comparable vs Comparator, generics and immutable collections.","java\u002Fcollections\u002Flist-map-set","Lists, Maps & Sets","2026-06-18","KKAzTsZlVi3cLtpI7VjbYaK-wgUwZoZPr2f6-GEaKnk",{"id":258,"title":259,"body":260,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":264,"navigation":108,"order":13,"path":265,"questions":266,"questionsCount":407,"related":250,"seo":408,"seoDescription":409,"stem":410,"subtopic":411,"topic":72,"topicSlug":74,"updated":255,"__hash__":412},"qa\u002Fjava\u002Fconcurrency\u002Fthreads.md","Threads",{"type":100,"value":261,"toc":262},[],{"title":103,"searchDepth":29,"depth":29,"links":263},[],{},"\u002Fjava\u002Fconcurrency\u002Fthreads",[267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375,379,383,387,391,395,399,403],{"id":268,"difficulty":113,"q":269,"a":270},"thread-vs-runnable","What are the ways to create a thread in Java?","Two basic approaches, plus the modern preferred one:\n\n- **Extend `Thread`** and override `run()` — simple, but uses up your single\n  inheritance slot.\n- **Implement `Runnable`** and pass it to a `Thread` — favored, because it\n  separates the task from the thread and works with executors.\n\n```java\n\u002F\u002F Runnable (preferred)\nRunnable task = () -> System.out.println(\"working\");\nnew Thread(task).start();\n\n\u002F\u002F extending Thread\nclass Worker extends Thread { public void run() { } }\n```\n\nIn real code you rarely create threads directly at all — you submit\n`Runnable`\u002F`Callable` tasks to an **`ExecutorService`**, which manages a pool\nfor you.\n",{"id":272,"difficulty":113,"q":273,"a":274},"start-vs-run","What is the difference between start() and run()?","**`start()`** asks the JVM to create a **new thread** and invoke `run()` on it —\nconcurrent execution. Calling **`run()`** directly just executes the method on\nthe **current** thread, like any ordinary call — no concurrency at all.\n\n```java\nThread t = new Thread(() -> System.out.println(Thread.currentThread().getName()));\nt.start();   \u002F\u002F prints \"Thread-0\" — runs on a new thread\nt.run();     \u002F\u002F prints \"main\"    — runs on the caller's thread\n```\n\nAlso, calling `start()` **twice** on the same `Thread` throws\n`IllegalThreadStateException` — a thread can be started only once.\n",{"id":276,"difficulty":105,"q":277,"a":278},"thread-lifecycle","What are the states in a thread's lifecycle?","A `Thread` moves through these `Thread.State` values:\n\n- **NEW** — created but not started.\n- **RUNNABLE** — eligible to run (running or waiting for CPU).\n- **BLOCKED** — waiting to acquire a monitor lock.\n- **WAITING** — waiting indefinitely (`wait()`, `join()`, `park()`).\n- **TIMED_WAITING** — waiting with a timeout (`sleep`, `wait(ms)`).\n- **TERMINATED** — finished or threw.\n\n```java\nThread t = new Thread(task);\nt.getState();  \u002F\u002F NEW\nt.start();\nt.getState();  \u002F\u002F RUNNABLE\n```\n\nTransitions are driven by the scheduler and synchronization calls; you observe\n(not directly set) the state.\n",{"id":280,"difficulty":105,"q":281,"a":282},"race-condition","What is a race condition?","A race condition occurs when **multiple threads access shared mutable state\nconcurrently** and the outcome depends on the **timing** of their interleaving.\nOperations that look atomic (like `count++`) are actually read-modify-write\nsequences that can interleave and lose updates.\n\n```java\nclass Counter {\n  int count;\n  void inc() { count++; } \u002F\u002F read, +1, write — NOT atomic\n}\n\u002F\u002F 1000 threads each calling inc() once -> final count often \u003C 1000\n```\n\nFixes: make the operation atomic (`synchronized`, `AtomicInteger`), or avoid\nshared mutable state. Race conditions are insidious because they're\n**intermittent** and timing-dependent.\n",{"id":284,"difficulty":105,"q":285,"a":286},"synchronized","What does the synchronized keyword do?","`synchronized` enforces **mutual exclusion**: only one thread can hold an\nobject's **monitor lock** at a time, so synchronized code runs serially. It also\nestablishes a **happens-before** relationship, guaranteeing memory visibility of\nchanges made under the lock.\n\n```java\nclass Counter {\n  private int count;\n  synchronized void inc() { count++; }      \u002F\u002F locks on `this`\n  void dec() {\n    synchronized (this) { count--; }        \u002F\u002F synchronized block\n  }\n}\n```\n\nA `synchronized` instance method locks on `this`; a `synchronized` static method\nlocks on the **`Class`** object. Keep critical sections small to limit\ncontention.\n",{"id":288,"difficulty":126,"q":289,"a":290},"volatile","What does volatile do and what does it not do?","`volatile` guarantees **visibility** and **ordering**: writes by one thread are\nimmediately visible to others (no per-thread caching), and it prevents\nreordering around the access. What it does **not** provide is **atomicity** for\ncompound operations.\n\n```java\nvolatile boolean running = true;  \u002F\u002F flag — visibility is enough\nvoid stop() { running = false; }  \u002F\u002F other threads see this promptly\n\nvolatile int count;\ncount++;   \u002F\u002F still a race — read-modify-write isn't atomic\n```\n\nUse `volatile` for **flags\u002Fstate published once** (the classic stop-flag), and\n`synchronized`\u002F`Atomic*` when you need atomic compound updates.\n",{"id":292,"difficulty":126,"q":293,"a":294},"synchronized-vs-volatile","What is the difference between synchronized and volatile?","- **`volatile`** — only **visibility + ordering** for a single variable. No\n  locking, no atomicity for compound ops. Cheap.\n- **`synchronized`** — **mutual exclusion + visibility**. Makes whole code\n  blocks atomic, can guard multiple variables, but threads can block on the\n  lock.\n\n```java\nvolatile boolean flag;       \u002F\u002F visibility only\nsynchronized void transfer() {  \u002F\u002F atomicity across several fields\n  from -= amt; to += amt;\n}\n```\n\nQuick rule: a single flag\u002Freference written-then-read -> `volatile`; a\nmulti-step invariant or counter -> `synchronized` (or an atomic\u002Flock).\n",{"id":296,"difficulty":126,"q":297,"a":298},"deadlock","What is a deadlock and how do you prevent it?","A deadlock is two+ threads each **holding a lock the other needs**, so all wait\nforever. It requires four conditions (Coffman): mutual exclusion, hold-and-wait,\nno preemption, and circular wait.\n\n```java\n\u002F\u002F Thread 1: lock A then B   |   Thread 2: lock B then A  -> deadlock\nsynchronized (a) { synchronized (b) { } }\nsynchronized (b) { synchronized (a) { } }\n```\n\nPrevention: acquire locks in a **consistent global order**, use **timeouts**\n(`tryLock`), reduce lock scope, or avoid multiple locks entirely. Breaking any\none Coffman condition (usually circular wait, via lock ordering) prevents\ndeadlock.\n",{"id":300,"difficulty":126,"q":301,"a":302},"livelock-starvation","What are livelock and starvation?","- **Starvation** — a thread is perpetually denied the resources\u002FCPU it needs\n  (e.g. low-priority threads, or always losing a lock to greedier ones), so it\n  never makes progress.\n- **Livelock** — threads are **actively running** but keep responding to each\n  other in a way that prevents progress (like two people stepping aside in the\n  same direction repeatedly).\n\n```java\n\u002F\u002F livelock sketch: both threads keep \"politely\" backing off\nwhile (other.isActive()) { backOff(); \u002F* never proceeds *\u002F }\n```\n\nUnlike deadlock (threads blocked), livelocked threads consume CPU. Fixes\ninclude randomized back-off, fairness policies, and bounded retries.\n",{"id":304,"difficulty":126,"q":305,"a":306},"wait-notify","How do wait(), notify() and notifyAll() work?","They coordinate threads on an object's monitor and **must be called while\nholding that object's lock** (inside `synchronized`). `wait()` releases the lock\nand suspends the thread until notified; `notify()` wakes one waiter,\n`notifyAll()` wakes all.\n\n```java\nsynchronized (queue) {\n  while (queue.isEmpty()) {   \u002F\u002F ALWAYS loop, never a bare if\n    queue.wait();             \u002F\u002F releases lock, waits\n  }\n  process(queue.remove());\n}\n\u002F\u002F producer:\nsynchronized (queue) { queue.add(item); queue.notifyAll(); }\n```\n\nAlways re-check the condition in a **`while`** loop (spurious wakeups + stale\nconditions). Prefer `notifyAll` unless you're certain one waiter suffices.\n",{"id":308,"difficulty":105,"q":309,"a":310},"sleep-vs-wait","What is the difference between sleep() and wait()?","- **`Thread.sleep(ms)`** — a static method that pauses the **current** thread\n  for a time **without releasing any locks** it holds. For timing\u002Fthrottling.\n- **`Object.wait()`** — an instance method that **releases the object's lock**\n  and waits to be notified; must be called inside `synchronized`. For\n  coordination between threads.\n\n```java\nsynchronized (lock) {\n  Thread.sleep(100);  \u002F\u002F keeps holding `lock` the whole time\n  lock.wait();        \u002F\u002F releases `lock` while waiting\n}\n```\n\nKey distinction: `sleep` keeps the lock, `wait` gives it up. Using `sleep` for\ninter-thread coordination is a classic anti-pattern.\n",{"id":312,"difficulty":105,"q":313,"a":314},"executor-service","What is an ExecutorService and why use a thread pool?","An `ExecutorService` manages a **pool of reusable threads** and a task queue, so\nyou submit work instead of creating threads by hand. This caps the thread count,\nreuses threads (avoiding creation overhead), and decouples task submission from\nexecution.\n\n```java\nExecutorService pool = Executors.newFixedThreadPool(4);\nFuture\u003CInteger> f = pool.submit(() -> compute());\npool.execute(() -> fireAndForget());\npool.shutdown();                 \u002F\u002F stop accepting; finish queued tasks\npool.awaitTermination(1, TimeUnit.MINUTES);\n```\n\nCreating a thread per task doesn't scale — unbounded threads exhaust memory and\nthrash the scheduler. Always `shutdown()` a pool to release its threads.\n",{"id":316,"difficulty":105,"q":317,"a":318},"thread-pool-types","What thread pool types does Executors provide?","- **`newFixedThreadPool(n)`** — fixed number of threads, unbounded queue.\n- **`newCachedThreadPool()`** — grows\u002Fshrinks on demand; reuses idle threads.\n- **`newSingleThreadExecutor()`** — one thread, sequential task processing.\n- **`newScheduledThreadPool(n)`** — for delayed\u002Fperiodic tasks.\n- **`newVirtualThreadPerTaskExecutor()`** (Java 21) — a virtual thread per task.\n\n```java\nvar scheduled = Executors.newScheduledThreadPool(2);\nscheduled.scheduleAtFixedRate(this::poll, 0, 5, TimeUnit.SECONDS);\n```\n\nIn production many teams construct **`ThreadPoolExecutor`** directly to control\nthe queue bounds and rejection policy, since `newFixedThreadPool`'s unbounded\nqueue can hide backpressure problems.\n",{"id":320,"difficulty":105,"q":321,"a":322},"callable-future","What is the difference between Runnable and Callable, and what is a Future?","- **`Runnable`** — `run()` returns **nothing** and can't throw checked\n  exceptions.\n- **`Callable\u003CV>`** — `call()` **returns a value** and may throw checked\n  exceptions.\n- **`Future\u003CV>`** — a handle to a pending result; `get()` blocks until it's\n  ready, `isDone()`\u002F`cancel()` manage it.\n\n```java\nCallable\u003CInteger> task = () -> 6 * 7;\nFuture\u003CInteger> f = pool.submit(task);\nInteger result = f.get();   \u002F\u002F blocks until done -> 42\n```\n\n`Future.get()` is **blocking**, which is its main weakness — addressed by\n`CompletableFuture`'s non-blocking composition.\n",{"id":324,"difficulty":126,"q":325,"a":326},"completablefuture","What is CompletableFuture and how does it improve on Future?","`CompletableFuture` is a `Future` you can **compose and chain\nasynchronously** — attaching callbacks instead of blocking on `get()`, and\ncombining multiple async results.\n\n```java\nCompletableFuture.supplyAsync(() -> fetchUser(id))\n    .thenApply(User::name)                 \u002F\u002F transform when ready\n    .thenCompose(name -> lookupAsync(name)) \u002F\u002F chain another async call\n    .exceptionally(ex -> \"fallback\")        \u002F\u002F handle errors\n    .thenAccept(System.out::println);       \u002F\u002F consume, non-blocking\n\nCompletableFuture.allOf(f1, f2, f3).join();  \u002F\u002F wait for several\n```\n\nIt enables a non-blocking pipeline (`thenApply`\u002F`thenCompose`\u002F`thenCombine`),\nbuilt-in error handling, and easy fan-out\u002Ffan-in — far more flexible than the\nblocking `Future`.\n",{"id":328,"difficulty":105,"q":329,"a":330},"atomic-classes","What are the atomic classes and how do they work?","`java.util.concurrent.atomic` provides lock-free, thread-safe variables —\n`AtomicInteger`, `AtomicLong`, `AtomicReference`, etc. They use **CAS\n(compare-and-swap)** hardware instructions for atomic updates without locking.\n\n```java\nAtomicInteger count = new AtomicInteger();\ncount.incrementAndGet();          \u002F\u002F atomic ++\ncount.compareAndSet(5, 10);       \u002F\u002F set to 10 only if currently 5\nref.updateAndGet(v -> v + delta); \u002F\u002F atomic functional update\n```\n\nAtomics outperform `synchronized` for simple counters\u002Fflags under contention\n(no blocking), though heavy contention can cause CAS retry loops. For high\ncontention prefer `LongAdder`.\n",{"id":332,"difficulty":126,"q":333,"a":334},"cas","What is compare-and-swap (CAS)?","CAS is an atomic CPU instruction: \"if this memory location still holds the\n*expected* value, replace it with the *new* value, atomically; otherwise do\nnothing and report failure.\" It's the foundation of **lock-free** algorithms.\n\n```java\n\u002F\u002F typical lock-free retry loop\nint prev, next;\ndo {\n  prev = atomic.get();\n  next = prev + 1;\n} while (!atomic.compareAndSet(prev, next)); \u002F\u002F retry if another thread changed it\n```\n\nBecause no lock is held, there's no blocking or deadlock — but it can spin under\ncontention, and it has the **ABA problem** (a value changing A->B->A looks\nunchanged), which `AtomicStampedReference` solves with a version stamp.\n",{"id":336,"difficulty":126,"q":337,"a":338},"reentrantlock","What is ReentrantLock and how does it compare to synchronized?","`ReentrantLock` is an explicit lock with the same mutual-exclusion semantics as\n`synchronized` but **more features**: `tryLock()` (with timeout), interruptible\nlocking, **fairness** policy, and multiple **`Condition`** objects.\n\n```java\nReentrantLock lock = new ReentrantLock();\nlock.lock();\ntry { \u002F* critical section *\u002F }\nfinally { lock.unlock(); }   \u002F\u002F MUST unlock in finally\n\nif (lock.tryLock(1, TimeUnit.SECONDS)) { ... }  \u002F\u002F give up after 1s\n```\n\nTrade-off: `synchronized` is simpler and auto-releases on block exit;\n`ReentrantLock` is more powerful but you **must** `unlock()` in `finally` or you\nleak the lock. Use it only when you need its extra capabilities.\n",{"id":340,"difficulty":126,"q":341,"a":342},"read-write-lock","What is a ReadWriteLock?","A `ReadWriteLock` separates a **read lock** (shared — many readers at once) from\na **write lock** (exclusive). It boosts throughput for **read-heavy** data where\nwrites are rare, since concurrent reads don't block each other.\n\n```java\nReadWriteLock rw = new ReentrantReadWriteLock();\nrw.readLock().lock();   try { return cache.get(k); } finally { rw.readLock().unlock(); }\nrw.writeLock().lock();  try { cache.put(k, v); }     finally { rw.writeLock().unlock(); }\n```\n\nOnly one writer runs at a time and it excludes all readers. For very read-heavy\ncases, `StampedLock` (Java 8) adds optimistic reads that are even faster.\n",{"id":344,"difficulty":126,"q":345,"a":346},"threadlocal","What is ThreadLocal and when is it used?","`ThreadLocal\u003CT>` gives **each thread its own independent copy** of a variable,\nso there's no sharing and no synchronization needed. Common for per-thread\ncontext: `SimpleDateFormat` (not thread-safe), user\u002Frequest context, DB\nconnections.\n\n```java\nstatic final ThreadLocal\u003CSimpleDateFormat> FMT =\n    ThreadLocal.withInitial(() -> new SimpleDateFormat(\"yyyy-MM-dd\"));\nString today = FMT.get().format(new Date());  \u002F\u002F safe per-thread instance\n```\n\nCaution in **thread pools**: threads are reused, so you must **`remove()`** the\nvalue after use or it leaks into the next task (and can cause memory leaks).\n",{"id":348,"difficulty":126,"q":349,"a":350},"java-memory-model","What is the Java Memory Model and happens-before?","The Java Memory Model (JMM) defines **when writes by one thread become visible to\nanother** and what reorderings are allowed. The core concept is\n**happens-before**: if action A happens-before B, A's effects are guaranteed\nvisible to B.\n\nHappens-before edges include: program order within a thread; unlocking a monitor\n-> subsequent locking of it; a `volatile` write -> subsequent read; `Thread.start`\n-> the thread's actions; a thread's actions -> another's `join`.\n\n```java\nvolatile boolean ready;\nint data;\n\u002F\u002F Thread A:\ndata = 42; ready = true;          \u002F\u002F volatile write publishes `data`\n\u002F\u002F Thread B:\nif (ready) System.out.println(data); \u002F\u002F sees 42 — happens-before guarantees it\n```\n\nWithout a happens-before relationship, one thread may **never** see another's\nwrites (or see them reordered). This is *why* `volatile`\u002F`synchronized` matter.\n",{"id":352,"difficulty":105,"q":353,"a":354},"thread-safety","What does it mean for code to be thread-safe?","Thread-safe code behaves **correctly when accessed by multiple threads\nconcurrently**, without external synchronization, regardless of timing. You\nachieve it by: avoiding shared mutable state, **immutability**,\n**synchronization**, atomic variables, or thread-confinement (`ThreadLocal`).\n\n```java\n\u002F\u002F thread-safe by immutability — no state can change\nrecord Point(int x, int y) { }\n\u002F\u002F thread-safe by synchronization\nclass SafeCounter { private int n; synchronized void inc() { n++; } }\n```\n\nLevels range from **immutable** (always safe) -> **thread-safe** (handles its own\nsync) -> **conditionally safe** (some ops need external sync) -> **not\nthread-safe** (`ArrayList`, `HashMap`). The cheapest safety is having no shared\nmutable state at all.\n",{"id":356,"difficulty":126,"q":357,"a":358},"producer-consumer","How do you implement the producer-consumer pattern?","Producers add items to a shared buffer, consumers remove them; they must\ncoordinate so producers wait when full and consumers wait when empty. The\nidiomatic modern way is a **`BlockingQueue`**, which handles all the\nwaiting\u002Fnotifying internally.\n\n```java\nBlockingQueue\u003CTask> queue = new LinkedBlockingQueue\u003C>(100);\n\n\u002F\u002F producer\nqueue.put(task);        \u002F\u002F blocks if the queue is full\n\n\u002F\u002F consumer\nTask t = queue.take();  \u002F\u002F blocks if the queue is empty\n```\n\n`put`\u002F`take` block automatically — no manual `wait`\u002F`notify`. `ArrayBlockingQueue`\n(bounded) gives natural backpressure; `LinkedBlockingQueue` can be bounded or\nunbounded.\n",{"id":360,"difficulty":105,"q":361,"a":362},"countdownlatch","What are CountDownLatch and CyclicBarrier?","Both are synchronization aids that make threads wait for each other:\n\n- **`CountDownLatch`** — threads wait until a counter reaches zero; **one-shot**\n  (can't be reset). \"Wait for N tasks to finish.\"\n- **`CyclicBarrier`** — a fixed number of threads wait for **each other** at a\n  barrier point; **reusable** across rounds.\n\n```java\nCountDownLatch latch = new CountDownLatch(3);\nfor (int i = 0; i \u003C 3; i++)\n  pool.submit(() -> { work(); latch.countDown(); });\nlatch.await();   \u002F\u002F main thread blocks until all 3 finish\n```\n\n`CountDownLatch` is for \"main waits for workers\"; `CyclicBarrier` is for \"workers\nsync up repeatedly.\" `Semaphore` is a related tool that limits concurrent access\nto N permits.\n",{"id":364,"difficulty":105,"q":365,"a":366},"daemon-thread","What is a daemon thread?","A daemon thread is a **background thread that does not prevent the JVM from\nexiting**. The JVM shuts down once only daemon threads remain, abruptly stopping\nthem (their `finally` blocks may not run). Used for support tasks like GC,\nhousekeeping, and monitoring.\n\n```java\nThread t = new Thread(this::poll);\nt.setDaemon(true);   \u002F\u002F must be set BEFORE start()\nt.start();\n```\n\nUser (non-daemon) threads, by contrast, **keep the JVM alive** until they finish.\nSet the daemon flag before `start()` — changing it after throws\n`IllegalThreadStateException`. Don't use daemons for work that must complete.\n",{"id":368,"difficulty":126,"q":369,"a":370},"thread-interruption","How does thread interruption work?","Interruption is a **cooperative** signal, not a forced stop. `interrupt()` sets a\nthread's interrupt flag; the thread must **check it** (`isInterrupted()`) or be\nin a blocking call that throws `InterruptedException`. There is no safe way to\nforcibly kill a thread (`Thread.stop()` is deprecated and dangerous).\n\n```java\nwhile (!Thread.currentThread().isInterrupted()) {\n  try {\n    doWork();\n    Thread.sleep(100);\n  } catch (InterruptedException e) {\n    Thread.currentThread().interrupt(); \u002F\u002F restore the flag, then exit\n    break;\n  }\n}\n```\n\nBest practice: when you catch `InterruptedException` and can't propagate it,\n**restore the interrupt status** with `Thread.currentThread().interrupt()` so\ncallers still see it.\n",{"id":372,"difficulty":105,"q":373,"a":374},"synchronized-collections-conc","Why is ConcurrentHashMap preferred over synchronized maps?","`Collections.synchronizedMap` locks the **entire map** for every operation, so\nthreads serialize even on unrelated keys — a bottleneck. `ConcurrentHashMap`\nuses **fine-grained locking \u002F CAS on individual bins**, allowing many threads to\nread and write different buckets concurrently.\n\n```java\nMap\u003CString,Integer> m = new ConcurrentHashMap\u003C>();\nm.merge(word, 1, Integer::sum);     \u002F\u002F atomic compound update, no global lock\nm.computeIfAbsent(k, x -> load(x)); \u002F\u002F atomic\n```\n\nIt also offers **atomic** compound methods (`merge`, `computeIfAbsent`,\n`putIfAbsent`) and fail-safe iteration. The result is dramatically better\nthroughput under concurrency.\n",{"id":376,"difficulty":126,"q":377,"a":378},"false-sharing","What is false sharing?","False sharing is a performance problem (not a correctness bug) where two threads\nmodify **different variables that happen to sit on the same CPU cache line**.\nEach write **invalidates the whole line** in the other core's cache, forcing\nexpensive cache-coherence traffic even though the variables are independent.\n\n```java\n\u002F\u002F a[0] and a[1] may share a cache line; two threads hammering them contend\nlong[] counters = new long[2];\n\u002F\u002F padding or @Contended separates hot fields onto different lines\n```\n\nMitigations: pad hot fields apart, use `@jdk.internal.vm.annotation.Contended`,\nor use `LongAdder`, which internally stripes counters across cells to avoid\ncontention.\n",{"id":380,"difficulty":113,"q":381,"a":382},"thread-priority","How do thread priorities work?","Each thread has a priority from 1 (`MIN_PRIORITY`) to 10 (`MAX_PRIORITY`),\ndefault 5. It's only a **hint** to the OS scheduler about relative importance —\nnot a guarantee. Behavior is platform-dependent and often ignored.\n\n```java\nThread t = new Thread(task);\nt.setPriority(Thread.MAX_PRIORITY);  \u002F\u002F best-effort hint only\n```\n\nDon't build correctness on priorities — they can't ensure ordering and, on some\nplatforms, do almost nothing. For real coordination use explicit synchronization\nor executor configuration.\n",{"id":384,"difficulty":105,"q":385,"a":386},"synchronized-static","What is the difference between a synchronized instance method and a static one?","The difference is **which lock** is acquired:\n\n- A `synchronized` **instance** method locks on **`this`** (the object). Two\n  threads on *different instances* don't contend.\n- A `synchronized` **static** method locks on the **`Class`** object, shared by\n  all instances.\n\n```java\nclass C {\n  synchronized void a() { }          \u002F\u002F locks on this instance\n  static synchronized void b() { }   \u002F\u002F locks on C.class (one global lock)\n}\n```\n\nA subtle bug: `a()` and `b()` use **different locks**, so they can run\nsimultaneously even though both are \"synchronized.\" Mixing instance and static\nsynchronization on shared state doesn't protect it.\n",{"id":388,"difficulty":126,"q":389,"a":390},"double-checked-locking","What is double-checked locking and why does it need volatile?","Double-checked locking lazily initializes a singleton while only locking on the\nfirst call:\n\n```java\nclass Singleton {\n  private static volatile Singleton instance;   \u002F\u002F volatile is essential\n  static Singleton get() {\n    if (instance == null) {                      \u002F\u002F 1st check (no lock)\n      synchronized (Singleton.class) {\n        if (instance == null) {                  \u002F\u002F 2nd check (locked)\n          instance = new Singleton();\n        }\n      }\n    }\n    return instance;\n  }\n}\n```\n\nWithout **`volatile`**, another thread could see a **partially constructed**\nobject: `instance = new Singleton()` isn't atomic (allocate, construct, assign),\nand reordering could publish the reference before construction finishes.\n`volatile` forbids that reordering. (An enum or holder-class singleton avoids the\nwhole issue.)\n",{"id":392,"difficulty":126,"q":393,"a":394},"blocking-vs-nonblocking","What is the difference between blocking and non-blocking algorithms?","- **Blocking** algorithms use locks; a thread that can't proceed is **suspended**\n  (BLOCKED\u002FWAITING) until the lock frees. Simple, but a slow\u002Fdead lock-holder\n  stalls others (and risks deadlock).\n- **Non-blocking** (lock-free) algorithms use **CAS** retry loops; a thread never\n  suspends — it retries until it succeeds. No deadlock, better scalability, but\n  harder to write and can livelock\u002Fspin.\n\n```java\n\u002F\u002F non-blocking counter\nAtomicLong c = new AtomicLong();\nc.incrementAndGet();   \u002F\u002F CAS loop under the hood — never blocks\n```\n\n`java.util.concurrent` provides both: `ReentrantLock`\u002F`BlockingQueue` (blocking)\nand `Atomic*`\u002F`ConcurrentLinkedQueue` (non-blocking).\n",{"id":396,"difficulty":126,"q":397,"a":398},"virtual-threads","What are virtual threads (Project Loom)?","Virtual threads (Java 21) are **lightweight threads managed by the JVM**, not the\nOS. Millions can exist at once because a blocked virtual thread is **unmounted**\nfrom its carrier OS thread, freeing it for other work. This makes the simple\n\"thread-per-request\" blocking style scale like async code.\n\n```java\ntry (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n  for (var task : tasks) executor.submit(task); \u002F\u002F a virtual thread each\n}\n```\n\nThey're cheap to create and ideal for **I\u002FO-bound** workloads (many tasks\nblocking on network\u002FDB). For CPU-bound work, platform threads sized to the cores\nare still the right tool — virtual threads don't add CPU.\n",{"id":400,"difficulty":105,"q":401,"a":402},"synchronization-overhead","What is lock contention and how do you reduce it?","Lock contention occurs when many threads compete for the **same lock**, so they\nserialize and queue up — throughput collapses as cores sit idle waiting. The fix\nis to reduce how often and how long threads hold shared locks.\n\nStrategies:\n- **Shrink the critical section** — hold the lock for as little code as possible.\n- **Lock striping** — split one lock into many (what `ConcurrentHashMap` does).\n- **Use atomics \u002F lock-free** structures for simple state.\n- **Immutable or thread-local** data to avoid sharing.\n- **Read-write locks** when reads dominate.\n\n```java\n\u002F\u002F whole method locked     \u002F\u002F lock only the shared mutation\nsynchronized void m() {       void m() {\n  var x = expensive();          var x = expensive();\n  shared.add(x);                synchronized (shared) { shared.add(x); }\n}                             }\n```\n",{"id":404,"difficulty":105,"q":405,"a":406},"executor-shutdown","How do you properly shut down an ExecutorService?","Use the standard two-phase shutdown so in-flight tasks finish and threads are\nreleased (a pool's non-daemon threads otherwise keep the JVM alive):\n\n```java\npool.shutdown();                      \u002F\u002F stop accepting new tasks\ntry {\n  if (!pool.awaitTermination(30, TimeUnit.SECONDS)) {\n    pool.shutdownNow();               \u002F\u002F interrupt running tasks\n    pool.awaitTermination(10, TimeUnit.SECONDS);\n  }\n} catch (InterruptedException e) {\n  pool.shutdownNow();\n  Thread.currentThread().interrupt();\n}\n```\n\n`shutdown()` is graceful (finish queued work); `shutdownNow()` interrupts active\ntasks and returns the unstarted ones. Forgetting to shut down a pool is a common\nresource\u002Fthread leak.\n",35,{"description":103},"Java concurrency interview questions — threads vs Runnable, synchronized, volatile, the memory model, deadlock, wait\u002Fnotify, executors, futures, CompletableFuture and atomic classes.","java\u002Fconcurrency\u002Fthreads","Threads & Synchronization","pVwCc9VKXhUagL48LjJ7mQ3w0q9QXl5R7rvAAMOlfik",{"id":414,"title":415,"body":416,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":420,"navigation":108,"order":13,"path":421,"questions":422,"questionsCount":555,"related":250,"seo":556,"seoDescription":557,"stem":558,"subtopic":415,"topic":63,"topicSlug":65,"updated":255,"__hash__":559},"qa\u002Fjava\u002Fexceptions\u002Fexception-handling.md","Exception Handling",{"type":100,"value":417,"toc":418},[],{"title":103,"searchDepth":29,"depth":29,"links":419},[],{},"\u002Fjava\u002Fexceptions\u002Fexception-handling",[423,427,431,435,439,443,447,451,455,459,463,467,471,475,479,483,487,491,495,499,503,507,511,515,519,523,527,531,535,539,543,547,551],{"id":424,"difficulty":113,"q":425,"a":426},"what-is-exception","What is an exception in Java?","An exception is an **object representing an abnormal event** that disrupts\nnormal flow — a division by zero, a missing file, a null dereference. When one\noccurs, the JVM creates an exception object and **propagates it up the call\nstack** until a matching `catch` handles it, or the thread terminates.\n\n```java\ntry {\n  int x = 10 \u002F 0;          \u002F\u002F throws ArithmeticException\n} catch (ArithmeticException e) {\n  System.out.println(\"Caught: \" + e.getMessage()); \u002F\u002F \"\u002F by zero\"\n}\n```\n\nExceptions separate error-handling code from the main logic and carry context\n(message + stack trace) to help diagnose what went wrong.\n",{"id":428,"difficulty":105,"q":429,"a":430},"exception-hierarchy","What does the Java exception hierarchy look like?","Everything throwable descends from **`Throwable`**, which splits into two\nbranches:\n\n- **`Error`** — serious problems the application shouldn't catch\n  (`OutOfMemoryError`, `StackOverflowError`). Unchecked.\n- **`Exception`** — conditions a program may want to handle.\n  - **`RuntimeException`** and its subclasses are **unchecked**.\n  - All other `Exception` subclasses are **checked**.\n\n```\nThrowable\n├── Error              (unchecked — don't catch)\n└── Exception\n    ├── RuntimeException   (unchecked)\n    └── IOException, SQLException... (checked)\n```\n\nSo \"checked vs unchecked\" is purely about whether the class sits under\n`RuntimeException`\u002F`Error` (unchecked) or elsewhere under `Exception` (checked).\n",{"id":432,"difficulty":105,"q":433,"a":434},"checked-vs-unchecked","What is the difference between checked and unchecked exceptions?","- **Checked** exceptions (subclasses of `Exception`, excluding\n  `RuntimeException`) are verified by the **compiler**: a method must either\n  `catch` them or declare `throws`. They represent recoverable, expected\n  conditions (`IOException`, `SQLException`).\n- **Unchecked** exceptions (`RuntimeException`\u002F`Error` subclasses) are **not**\n  compiler-enforced — usually programming bugs (`NullPointerException`,\n  `IllegalArgumentException`, `ArrayIndexOutOfBoundsException`).\n\n```java\nvoid read() throws IOException {     \u002F\u002F checked -> must declare or catch\n  Files.readString(Path.of(\"x\"));\n}\nvoid bug() {\n  String s = null;\n  s.length();                        \u002F\u002F unchecked -> no declaration required\n}\n```\n\nGuideline: checked for conditions callers can reasonably recover from;\nunchecked for bugs and contract violations.\n",{"id":436,"difficulty":105,"q":437,"a":438},"error-vs-exception","What is the difference between Error and Exception?","Both extend `Throwable`, but:\n\n- **`Error`** signals a serious, usually **unrecoverable** JVM\u002Fsystem problem —\n  `OutOfMemoryError`, `StackOverflowError`, `NoClassDefFoundError`. Applications\n  **should not catch** these; there's typically nothing useful to do.\n- **`Exception`** signals an **application-level** condition that code may\n  reasonably handle.\n\n```java\ntry {\n  recurse();                  \u002F\u002F infinite recursion\n} catch (StackOverflowError e) {\n  \u002F\u002F technically possible, but a code smell — don't rely on this\n}\n```\n\nBoth are unchecked (well, `Error` is), but the intent differs: `Error` = \"the\nplatform is broken\"; `Exception` = \"your program hit a handleable situation.\"\n",{"id":440,"difficulty":113,"q":441,"a":442},"try-catch-finally","What are try, catch and finally blocks?","- **`try`** — wraps code that might throw.\n- **`catch`** — handles a specific exception type (you can have several).\n- **`finally`** — runs **always**, whether or not an exception occurred (and\n  even after a `return`) — for cleanup like closing resources.\n\n```java\ntry {\n  risky();\n} catch (IOException e) {\n  log(e);\n} finally {\n  cleanup();   \u002F\u002F runs no matter what\n}\n```\n\nA `try` needs at least one `catch` **or** a `finally`. `catch` blocks are checked\ntop-down, so order **subclasses before superclasses**.\n",{"id":444,"difficulty":126,"q":445,"a":446},"finally-always-runs","Does finally always run? Are there exceptions?","`finally` runs after the `try`\u002F`catch` in virtually all cases — including when\nthe `try` or `catch` executes a `return`, `break`, or `continue`. The **only**\nways to skip it: `System.exit()`, the JVM crashing, an infinite loop\u002Fdeadlock in\nthe `try`, or the thread being killed.\n\n```java\nint f() {\n  try {\n    return 1;     \u002F\u002F evaluated...\n  } finally {\n    System.out.println(\"still runs\"); \u002F\u002F ...but finally runs before returning\n  }\n}\n```\n\nBeware: a `return` (or `throw`) **inside `finally`** overrides the try's return\nand **swallows pending exceptions** — a notorious bug, so never return\u002Fthrow\nfrom `finally`.\n",{"id":448,"difficulty":105,"q":449,"a":450},"try-with-resources","What is try-with-resources?","A `try` with resources declared in parentheses **auto-closes** them when the\nblock exits — normally or via exception — as long as they implement\n`AutoCloseable`. It replaces verbose `finally { x.close(); }` blocks and avoids\nleaks.\n\n```java\ntry (var br = Files.newBufferedReader(path);\n     var conn = dataSource.getConnection()) {\n  return br.readLine();\n}   \u002F\u002F br and conn closed automatically, in reverse order\n```\n\nResources close in **reverse order** of declaration. It also handles the case\nwhere both the body *and* `close()` throw — see suppressed exceptions.\n",{"id":452,"difficulty":105,"q":453,"a":454},"autocloseable","What is AutoCloseable and how do you use it?","`AutoCloseable` is the interface (one method, `close()`) that makes a class\neligible for **try-with-resources**. Implement it for any resource that needs\ndeterministic cleanup — connections, streams, locks.\n\n```java\nclass Connection implements AutoCloseable {\n  Connection() { System.out.println(\"open\"); }\n  public void close() { System.out.println(\"closed\"); }\n}\ntry (Connection c = new Connection()) {\n  \u002F\u002F use c\n} \u002F\u002F close() called automatically\n```\n\n`Closeable` (from `java.io`) extends `AutoCloseable` but narrows `close()` to\nthrow `IOException`. Prefer `AutoCloseable` for general resources.\n",{"id":456,"difficulty":105,"q":457,"a":458},"multi-catch","What is multi-catch and when is it useful?","Multi-catch (Java 7+) handles **several exception types in one `catch`** using\nthe `|` separator, when the handling logic is identical — reducing duplication.\n\n```java\ntry {\n  parseAndStore();\n} catch (IOException | SQLException e) {   \u002F\u002F one handler for both\n  log.error(\"operation failed\", e);\n  throw new ServiceException(e);\n}\n```\n\nRules: the types must **not be subclasses of one another** (redundant), and the\ncaught variable `e` is **implicitly final**. Use it to collapse copy-pasted\ncatch blocks.\n",{"id":460,"difficulty":113,"q":461,"a":462},"throw-vs-throws","What is the difference between throw and throws?","- **`throw`** is a **statement** that actually raises an exception object, now.\n- **`throws`** is a **method declaration** clause announcing which checked\n  exceptions the method may propagate to its caller.\n\n```java\nvoid withdraw(int amt) throws InsufficientFundsException { \u002F\u002F declares\n  if (amt > balance) {\n    throw new InsufficientFundsException(); \u002F\u002F raises\n  }\n}\n```\n\nMnemonic: `throw` *does* it (one object), `throws` *warns about* it (a list of\ntypes). You can `throw` unchecked exceptions without declaring them.\n",{"id":464,"difficulty":105,"q":465,"a":466},"custom-exception","How do you create a custom exception?","Extend `Exception` (for checked) or `RuntimeException` (for unchecked), and\nprovide constructors that pass the message and cause to `super`.\n\n```java\npublic class InsufficientFundsException extends RuntimeException {\n  private final int shortfall;\n  public InsufficientFundsException(int shortfall) {\n    super(\"Short by \" + shortfall + \" cents\");\n    this.shortfall = shortfall;\n  }\n  public int getShortfall() { return shortfall; }\n}\n```\n\nCustom exceptions let you carry **domain-specific data** and let callers\n`catch` precisely. Prefer **unchecked** for programming\u002Fbusiness errors unless\nthe caller can genuinely recover (then checked).\n",{"id":468,"difficulty":105,"q":469,"a":470},"exception-chaining","What is exception chaining (the cause)?","Exception chaining wraps a low-level exception inside a higher-level one while\n**preserving the original as the \"cause\"**, so the full diagnostic trail\nsurvives. Pass the cause to the constructor or `initCause`.\n\n```java\ntry {\n  jdbc.query();\n} catch (SQLException e) {\n  throw new DataAccessException(\"load failed\", e); \u002F\u002F e becomes the cause\n}\n```\n\nThe printed stack trace shows `Caused by: java.sql.SQLException...`. Chaining\nlets you translate exceptions across abstraction layers without losing the root\ncause — far better than catching and re-throwing a bare new exception.\n",{"id":472,"difficulty":126,"q":473,"a":474},"swallowing","What does it mean to \"swallow\" an exception and why is it bad?","Swallowing is catching an exception and **doing nothing** (or only an empty\nblock), hiding the failure so the program continues in a possibly broken state\nand you lose all diagnostic information.\n\n```java\n\u002F\u002F swallowed — silent failure, impossible to debug\ntry { risky(); } catch (Exception e) { }\n\n\u002F\u002F at minimum, log it (and preserve the stack trace)\ntry { risky(); } catch (Exception e) {\n  log.error(\"risky() failed\", e);\n  throw e;                 \u002F\u002F or wrap\u002Frethrow if you can't handle it\n}\n```\n\nRule: never have an empty catch. Either **handle** it meaningfully, **log** it,\nor **rethrow**. Empty catches are one of the most damaging anti-patterns in\nproduction code.\n",{"id":476,"difficulty":105,"q":477,"a":478},"catch-order","Why does catch block order matter?","`catch` blocks are evaluated **top to bottom**, and the first matching type\nwins. So a **more specific** exception must come **before** its superclass —\notherwise the broad catch shadows the specific one and the compiler reports\n\"exception has already been caught.\"\n\n```java\ntry {\n  read();\n} catch (FileNotFoundException e) {  \u002F\u002F specific first\n  \u002F\u002F handle missing file\n} catch (IOException e) {            \u002F\u002F broader after\n  \u002F\u002F handle other I\u002FO errors\n}\n```\n\nReversing them (`IOException` first) is a **compile error**, because\n`FileNotFoundException` could never be reached.\n",{"id":480,"difficulty":113,"q":481,"a":482},"npe-causes","What causes a NullPointerException and how do you prevent it?","An NPE happens when you **dereference `null`** — call a method, access a field,\nindex an array, or unbox a null wrapper.\n\n```java\nString s = map.get(\"missing\"); \u002F\u002F null\ns.length();                    \u002F\u002F NullPointerException\n```\n\nPrevention: validate inputs (`Objects.requireNonNull`), use `Optional` for\nmaybe-absent values, prefer constants on the left of `equals`\n(`\"x\".equals(s)`), use `getOrDefault`, and embrace **Java 14+ helpful NPE\nmessages** which name the exact expression that was null\n(`Cannot invoke \"String.length()\" because \"s\" is null`).\n",{"id":484,"difficulty":105,"q":485,"a":486},"optional","How does Optional help with null handling?","`Optional\u003CT>` is a container that **explicitly represents \"value or absent,\"**\nforcing callers to deal with the empty case instead of risking an NPE on a\nsurprise null.\n\n```java\nOptional\u003CUser> user = repo.findById(id);\nString name = user.map(User::name)\n                  .orElse(\"unknown\");        \u002F\u002F default if absent\nuser.ifPresent(u -> sendEmail(u));           \u002F\u002F act only if present\n```\n\nBest practices: use it as a **return type** for \"might not find one\"; **don't**\nuse it for fields, parameters, or collections (return an empty collection\ninstead); and avoid `.get()` without checking (`isPresent`\u002F`orElseThrow`).\n",{"id":488,"difficulty":113,"q":489,"a":490},"stack-trace","What is a stack trace and how do you read it?","A stack trace is the **snapshot of the call stack** at the moment an exception\nwas created — it lists, top to bottom, the method calls from where the\nexception was thrown back up to the entry point.\n\n```\njava.lang.NullPointerException: ... \"user\" is null\n    at com.app.Service.process(Service.java:42)   \u003C- where it was thrown\n    at com.app.Controller.handle(Controller.java:18)\n    at com.app.Main.main(Main.java:9)\nCaused by: java.sql.SQLException: ...             \u003C- original cause\n```\n\nRead the **top frame** for where it blew up, and follow **`Caused by:`** down to\nthe root cause. Print it with `e.printStackTrace()` or, better, `log.error(msg,\ne)`.\n",{"id":492,"difficulty":126,"q":493,"a":494},"finally-return-trap","What happens when both try and finally have a return?","A `return` in `finally` **overrides** any return or exception from the `try`\u002F\n`catch` — the try's pending result (or thrown exception) is **discarded\nsilently**. This is a subtle, dangerous bug.\n\n```java\nint f() {\n  try {\n    return 1;\n  } finally {\n    return 2;   \u002F\u002F method returns 2; the \"return 1\" is lost\n  }\n}\nint g() {\n  try {\n    throw new RuntimeException();\n  } finally {\n    return 0;   \u002F\u002F swallows the exception entirely\n  }\n}\n```\n\nNever put `return`\u002F`throw`\u002F`break` in `finally`. Use `finally` strictly for\ncleanup, not control flow.\n",{"id":496,"difficulty":126,"q":497,"a":498},"suppressed-exceptions","What are suppressed exceptions?","In try-with-resources, if the **body throws** *and* `close()` also throws, Java\nkeeps the body's exception as primary and attaches the close exception as a\n**suppressed** exception (so neither is lost). You retrieve them via\n`getSuppressed()`.\n\n```java\ntry (AutoCloseable r = () -> { throw new IOException(\"close failed\"); }) {\n  throw new RuntimeException(\"body failed\"); \u002F\u002F primary\n}\n\u002F\u002F RuntimeException propagates; the IOException is in getSuppressed()\n```\n\nBefore try-with-resources, a `close()` exception in a manual `finally` would\n*replace* the original — hiding the real cause. Suppression fixes that. The\nprintout shows `Suppressed:` beneath the main trace.\n",{"id":500,"difficulty":105,"q":501,"a":502},"rethrow","What are the ways to rethrow an exception?","- **Rethrow as-is** — let it propagate after partial handling (log, then\n  `throw e`).\n- **Wrap and rethrow** — translate to a higher-level type, preserving the cause\n  (`throw new ServiceException(e)`).\n- **Rethrow a different type** — only when it improves the abstraction.\n\n```java\ntry {\n  repo.save(order);\n} catch (SQLException e) {\n  metrics.increment(\"save.failure\");\n  throw new PersistenceException(\"could not save order\", e); \u002F\u002F wrap + chain\n}\n```\n\nAlways pass the original as the **cause** when wrapping, so debugging info\nsurvives. Don't catch just to rethrow the *same* type with no added value.\n",{"id":504,"difficulty":105,"q":505,"a":506},"best-practices","What are best practices for exception handling?","- **Catch specific** exceptions, not bare `Exception`\u002F`Throwable`.\n- **Never swallow** — handle, log, or rethrow.\n- **Throw early, catch late** — validate inputs at the boundary; handle where\n  you have context to recover.\n- **Don't use exceptions for control flow** (they're expensive and obscure\n  intent).\n- **Preserve the cause** when wrapping.\n- **Clean up with try-with-resources**, not manual `finally`.\n- Include **useful messages** with context.\n\n```java\n\u002F\u002F specific, contextual, chained\ncatch (IOException e) {\n  throw new ConfigException(\"failed to load \" + path, e);\n}\n```\n",{"id":508,"difficulty":126,"q":509,"a":510},"exception-performance","Why are exceptions expensive, and what is the cost?","The main cost is **capturing the stack trace** when the exception is\nconstructed — the JVM walks the entire call stack and records each frame. The\n`throw`\u002F`catch` mechanism itself is cheap; building the trace is not. So using\nexceptions for ordinary control flow (e.g. loop termination) is slow.\n\n```java\n\u002F\u002F for hot paths where the trace isn't needed, you can disable it:\nclass FastException extends RuntimeException {\n  FastException() { super(null, null, false, false); } \u002F\u002F no stack trace\n}\n```\n\nGuidance: reserve exceptions for **exceptional** conditions; use return values,\n`Optional`, or sentinels for expected outcomes. Don't catch-and-ignore in tight\nloops.\n",{"id":512,"difficulty":105,"q":513,"a":514},"custom-checked-or-unchecked","Should a custom exception be checked or unchecked?","Decide by whether the **caller can reasonably recover**:\n\n- **Checked** (`extends Exception`) — recoverable, expected conditions the\n  caller should be forced to handle (e.g. `FileNotFoundException`-like cases).\n- **Unchecked** (`extends RuntimeException`) — programming errors, contract\n  violations, or failures the caller usually can't fix (validation,\n  configuration, most business-rule violations).\n\n```java\n\u002F\u002F recoverable -> checked\nclass RetryableNetworkException extends Exception { }\n\u002F\u002F bug \u002F unrecoverable -> unchecked\nclass InvalidConfigException extends RuntimeException { }\n```\n\nModern frameworks (Spring, etc.) lean heavily toward **unchecked** to avoid\n`throws` clutter, translating low-level checked exceptions into runtime ones.\n",{"id":516,"difficulty":126,"q":517,"a":518},"catch-throwable","Why should you avoid catching Throwable or Exception broadly?","Catching `Throwable` also catches **`Error`s** (`OutOfMemoryError`,\n`StackOverflowError`) that you can't sensibly recover from and may make things\nworse. Catching `Exception` broadly hides bugs (an unexpected\n`NullPointerException` gets swallowed by a handler meant for I\u002FO errors).\n\n```java\n\u002F\u002F too broad — masks programming bugs and serious errors\ntry { work(); } catch (Throwable t) { \u002F* keep going *\u002F }\n\n\u002F\u002F catch what you can actually handle\ntry { work(); } catch (IOException e) { recover(e); }\n```\n\nCatch the **narrowest** type that you genuinely know how to handle; let\neverything else propagate to a top-level handler.\n",{"id":520,"difficulty":105,"q":521,"a":522},"exception-translation","What is exception translation across layers?","Exception translation means **converting low-level exceptions into ones\nappropriate to the current abstraction layer**, so callers aren't coupled to\nimplementation details (a service shouldn't leak `SQLException`).\n\n```java\n\u002F\u002F persistence layer hides JDBC details from the service layer\ntry {\n  return jdbcTemplate.query(sql);\n} catch (SQLException e) {\n  throw new RepositoryException(\"query failed\", e); \u002F\u002F translate + chain\n}\n```\n\nAlways keep the original as the cause. This is exactly what Spring's\n`DataAccessException` hierarchy does — translating vendor-specific SQL errors\ninto a consistent, unchecked API.\n",{"id":524,"difficulty":105,"q":525,"a":526},"assert","What is the assert keyword and how does it relate to exceptions?","`assert` checks an invariant that should *always* be true; if false it throws an\n`AssertionError`. Assertions are **disabled by default** at runtime (enable with\nthe `-ea` JVM flag), so they're for **catching developer bugs during\ndevelopment\u002Ftesting**, not validating production input.\n\n```java\nassert index >= 0 : \"index must be non-negative, got \" + index;\n```\n\nBecause they can be turned off, **never** use `assert` for argument validation\nor anything with side effects — use `if (...) throw new\nIllegalArgumentException(...)` for real input checks.\n",{"id":528,"difficulty":105,"q":529,"a":530},"nested-try","How do nested try blocks and exception propagation work?","A `try` can contain another `try`. If an inner block doesn't catch an\nexception, it **propagates outward** to the nearest enclosing handler — and\nkeeps unwinding the stack until something catches it or the thread dies.\n\n```java\ntry {\n  try {\n    throw new IllegalStateException(\"inner\");\n  } finally {\n    System.out.println(\"inner finally\"); \u002F\u002F runs during unwind\n  }\n} catch (IllegalStateException e) {\n  System.out.println(\"caught in outer\"); \u002F\u002F handled here\n}\n```\n\nDuring propagation, every `finally` along the way still executes. This unwinding\nis how an exception thrown deep in the call stack reaches a top-level handler.\n",{"id":532,"difficulty":126,"q":533,"a":534},"uncaught-handler","What happens to an uncaught exception in a thread?","If an exception propagates out of a thread's `run`\u002F`main` without being caught,\nthe thread **terminates**, and the JVM hands the exception to that thread's\n**`UncaughtExceptionHandler`** (by default printing the stack trace to\n`System.err`). Other threads keep running; the **whole JVM only exits if it was\nthe last non-daemon thread**.\n\n```java\nThread.setDefaultUncaughtExceptionHandler((t, e) ->\n    log.error(\"Uncaught in \" + t.getName(), e));\n```\n\nSetting a handler is essential for background threads, whose failures would\notherwise vanish silently.\n",{"id":536,"difficulty":105,"q":537,"a":538},"illegalargument-vs-illegalstate","When do you use IllegalArgumentException vs IllegalStateException?","Both are standard unchecked exceptions for **precondition violations**:\n\n- **`IllegalArgumentException`** — a **method argument** is invalid (wrong\n  value\u002Frange).\n- **`IllegalStateException`** — the **object is in the wrong state** for the\n  operation, regardless of the arguments.\n\n```java\nvoid setAge(int age) {\n  if (age \u003C 0) throw new IllegalArgumentException(\"age \u003C 0: \" + age);\n}\nvoid start() {\n  if (running) throw new IllegalStateException(\"already started\");\n}\n```\n\nUse the built-in exceptions (plus `NullPointerException` for null args,\nidiomatically via `Objects.requireNonNull`) rather than inventing custom ones\nfor these common cases.\n",{"id":540,"difficulty":105,"q":541,"a":542},"finally-resource-leak","Why is manual finally cleanup error-prone compared to try-with-resources?","Manual cleanup in `finally` is verbose and easy to get wrong: you must\nnull-check, nest try\u002Fcatch around `close()`, and handle the case where `close()`\nitself throws (which would hide the original exception). Multiple resources\nmultiply the boilerplate.\n\n```java\n\u002F\u002F error-prone manual style\nBufferedReader br = null;\ntry {\n  br = Files.newBufferedReader(path);\n} finally {\n  if (br != null) br.close(); \u002F\u002F close() can throw and mask the real error\n}\n\n\u002F\u002F correct, concise, handles suppression\ntry (var br = Files.newBufferedReader(path)) { }\n```\n\nTry-with-resources closes in the right order, handles nulls, and records\nsuppressed exceptions — strictly better.\n",{"id":544,"difficulty":126,"q":545,"a":546},"rethrow-precise","What is more precise rethrow analysis (Java 7+)?","Since Java 7, the compiler analyzes which checked exceptions can **actually**\nflow out of a `try`, so you can catch a broad type but **rethrow with a\nnarrower `throws`** clause — as long as the caught variable is effectively\nfinal.\n\n```java\nvoid m() throws IOException, SQLException {  \u002F\u002F precise, not \"throws Exception\"\n  try {\n    if (cond) throw new IOException();\n    else throw new SQLException();\n  } catch (Exception e) {   \u002F\u002F catch broadly...\n    log(e);\n    throw e;                \u002F\u002F ...rethrow: compiler knows it's IOException|SQLException\n  }\n}\n```\n\nBefore Java 7 you'd have been forced to declare `throws Exception`. This lets you\nlog centrally while keeping precise method signatures.\n",{"id":548,"difficulty":126,"q":549,"a":550},"exception-in-static-init","What happens if an exception is thrown in a static initializer?","If a `static` initializer (or static field initialization) throws, the JVM wraps\nit in an **`ExceptionInInitializerError`** and the class **fails to initialize**.\nWorse, the class is marked unusable: any later attempt to use it throws\n**`NoClassDefFoundError`**.\n\n```java\nclass Config {\n  static final int VALUE = compute(); \u002F\u002F if compute() throws...\n  static int compute() { throw new RuntimeException(\"boom\"); }\n}\n\u002F\u002F First use -> ExceptionInInitializerError\n\u002F\u002F Subsequent uses -> NoClassDefFoundError\n```\n\nThis is a confusing failure mode in real systems — a misconfigured static\nconstant can make a class permanently unloadable. Keep static initialization\nsimple and defensive.\n",{"id":552,"difficulty":105,"q":553,"a":554},"logging-vs-throwing","Should you log and throw, or just one?","Doing **both** at every level causes \"log spam\" — the same exception printed\nrepeatedly as it propagates. The common rule: **either handle it (and log) OR\npropagate it (and let a higher layer log)** — not both at every level.\n\n```java\n\u002F\u002F log-and-throw at every layer -> duplicated stack traces\ncatch (IOException e) { log.error(\"failed\", e); throw e; }\n\n\u002F\u002F propagate now, log once at the top-level boundary\ncatch (IOException e) { throw new ServiceException(e); }\n\u002F\u002F ... and a single handler at the controller\u002Fedge logs it\n```\n\nLog **once**, at the boundary where the exception is finally handled (e.g. a\ncontroller advice or a top-level `catch`), with full context.\n",33,{"description":103},"Java exception handling interview questions — checked vs unchecked, the exception hierarchy, try\u002Fcatch\u002Ffinally, try-with-resources, custom exceptions, chaining, and common pitfalls like swallowing exceptions.","java\u002Fexceptions\u002Fexception-handling","yZ7jJ_94rqM_RCNc5k2-7A9tK3XdpOb1VxM5FboQycU",{"id":561,"title":562,"body":563,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":567,"navigation":108,"order":13,"path":568,"questions":569,"questionsCount":555,"related":250,"seo":702,"seoDescription":703,"stem":704,"subtopic":705,"topic":20,"topicSlug":21,"updated":255,"__hash__":706},"qa\u002Fjava\u002Ffundamentals\u002Fdata-types-variables.md","Data Types Variables",{"type":100,"value":564,"toc":565},[],{"title":103,"searchDepth":29,"depth":29,"links":566},[],{},"\u002Fjava\u002Ffundamentals\u002Fdata-types-variables",[570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646,650,654,658,662,666,670,674,678,682,686,690,694,698],{"id":571,"difficulty":113,"q":572,"a":573},"primitives-list","What are the eight primitive types in Java?","Java has exactly **eight** primitives, each with a fixed size and no methods:\n\n| Type | Size | Range \u002F notes |\n| ---- | ---- | ------------- |\n| `byte` | 8-bit | −128…127 |\n| `short` | 16-bit | −32,768…32,767 |\n| `int` | 32-bit | ~±2.1 billion (default for integer literals) |\n| `long` | 64-bit | very large; literal suffix `L` |\n| `float` | 32-bit | IEEE-754, suffix `f` |\n| `double` | 64-bit | IEEE-754 (default for decimal literals) |\n| `char` | 16-bit | a single UTF-16 code unit, `0`…`65535` |\n| `boolean` | JVM-defined | `true` \u002F `false` |\n\nPrimitives hold their value **directly** (on the stack or inline in an\nobject), unlike objects which are accessed through references. Everything else\nin Java — `String`, arrays, your classes — is a reference type.\n",{"id":575,"difficulty":113,"q":576,"a":577},"primitive-vs-wrapper","What is the difference between a primitive and its wrapper class?","Every primitive has an **object wrapper** in `java.lang`: `int`->`Integer`,\n`double`->`Double`, `char`->`Character`, `boolean`->`Boolean`, etc. The primitive\nstores a raw value; the wrapper is a full **object** on the heap that *contains*\nthe value plus object overhead (header, identity, can be `null`).\n\n```java\nint a = 5;              \u002F\u002F raw value, can never be null\nInteger b = 5;          \u002F\u002F object reference, can be null\nInteger c = null;       \u002F\u002F legal; int x = c; would throw NullPointerException\n```\n\nYou need wrappers wherever Java requires an object: generics\n(`List\u003CInteger>`, never `List\u003Cint>`), collections, and nullable fields.\nPrimitives are faster and lighter, so prefer them for arithmetic and hot loops.\n",{"id":579,"difficulty":105,"q":580,"a":581},"autoboxing","What are autoboxing and unboxing?","**Autoboxing** is the compiler automatically converting a primitive to its\nwrapper; **unboxing** is the reverse. It lets primitives and wrappers mix\nseamlessly — `Integer.valueOf(...)` \u002F `intValue()` calls are inserted for you.\n\n```java\nList\u003CInteger> nums = new ArrayList\u003C>();\nnums.add(5);            \u002F\u002F autobox: int 5 -> Integer.valueOf(5)\nint first = nums.get(0); \u002F\u002F unbox: Integer -> intValue()\n```\n\nThe hidden cost: unboxing a `null` wrapper throws **`NullPointerException`**,\nand boxing in a tight loop creates throwaway objects (GC pressure). A classic\ntrap is `Integer sum = 0; for (...) sum += x;` which boxes\u002Funboxes every\niteration — use a primitive `int` accumulator instead.\n",{"id":583,"difficulty":126,"q":584,"a":585},"integer-cache","Why does == sometimes return true and sometimes false for equal Integer values?","Because `==` on wrappers compares **references**, and Java **caches** boxed\n`Integer` objects for the range **−128 to 127** (the `IntegerCache`). Values in\nthat range return the *same* cached object; values outside it create new\nobjects each time.\n\n```java\nInteger a = 127, b = 127;\nSystem.out.println(a == b);   \u002F\u002F true  — same cached object\n\nInteger c = 128, d = 128;\nSystem.out.println(c == d);   \u002F\u002F false — two distinct objects\nSystem.out.println(c.equals(d)); \u002F\u002F true — value comparison\n```\n\nThe lesson interviewers want: **always compare wrapper values with\n`.equals()`** (or unbox to primitives), never `==`. The cache exists because\nsmall integers are extremely common, so reusing them saves allocations.\n",{"id":587,"difficulty":113,"q":588,"a":589},"equals-vs-eqeq","What is the difference between == and .equals() in Java?","`==` compares **references** for objects (do both variables point to the *same*\nobject?) and raw **values** for primitives. `.equals()` is a method that\ncompares **logical equality** — what \"equal\" means is defined by the class.\n\n```java\nString a = new String(\"hi\");\nString b = new String(\"hi\");\na == b        \u002F\u002F false — two different objects\na.equals(b)   \u002F\u002F true  — same characters\n\nint x = 5, y = 5;\nx == y        \u002F\u002F true  — primitive value comparison\n```\n\n`Object.equals` defaults to `==` (reference identity), so a class must\n**override** `equals` to get meaningful value comparison — `String`,\n`Integer`, and the collections all do.\n",{"id":591,"difficulty":105,"q":592,"a":593},"string-immutable","Why are Strings immutable in Java?","A `String`'s internal character data is `final` and never changes after\nconstruction; any \"modification\" returns a **new** `String`. Immutability buys\nseveral things: **safe sharing** in the string pool, **thread safety** without\nlocks, usability as **hash keys** (the hash can be cached and never goes\nstale), and **security** (a path\u002FURL can't be mutated after a check).\n\n```java\nString s = \"hello\";\ns.concat(\" world\");      \u002F\u002F creates a new String, discarded here\nSystem.out.println(s);   \u002F\u002F \"hello\" — s itself is unchanged\ns = s.concat(\" world\");  \u002F\u002F reassign the reference to the new String\n```\n\nThe trade-off is that heavy string building creates garbage — which is exactly\nwhy `StringBuilder` exists.\n",{"id":595,"difficulty":105,"q":596,"a":597},"string-pool","What is the String pool (string interning)?","The string pool is a special area where the JVM stores **one shared copy** of\neach distinct string **literal**. Two identical literals refer to the same\npooled object, saving memory. Strings made with `new` are *not* pooled — they\ncreate a fresh heap object — unless you call `.intern()`.\n\n```java\nString a = \"hi\";          \u002F\u002F pooled\nString b = \"hi\";          \u002F\u002F same pooled object\nString c = new String(\"hi\"); \u002F\u002F new heap object, NOT pooled\na == b           \u002F\u002F true\na == c           \u002F\u002F false\na == c.intern()  \u002F\u002F true — intern() returns the pooled copy\n```\n\nThis is why beginners hit bugs comparing strings with `==`: literals seem to\nwork (same pooled object) but `new`\u002Fcomputed strings don't. Always use\n`.equals()`.\n",{"id":599,"difficulty":105,"q":600,"a":601},"stringbuilder","What is the difference between String, StringBuilder and StringBuffer?","- **`String`** — immutable; every concatenation allocates a new object. Fine\n  for a few fixed pieces, wasteful in loops.\n- **`StringBuilder`** — a **mutable**, resizable character buffer. Not\n  synchronized, so it's fast; the right default for building strings.\n- **`StringBuffer`** — same API as `StringBuilder` but **synchronized**\n  (thread-safe), hence slower. Rarely needed today.\n\n```java\n\u002F\u002F O(n²) garbage — a new String each iteration\nString r = \"\";\nfor (String p : parts) r += p;\n\n\u002F\u002F one buffer, amortized O(n)\nStringBuilder sb = new StringBuilder();\nfor (String p : parts) sb.append(p);\nString r2 = sb.toString();\n```\n\nNote the compiler optimizes simple `a + b + c` into `StringBuilder` calls — the\nproblem is concatenation **inside loops**, where it can't.\n",{"id":603,"difficulty":126,"q":604,"a":605},"pass-by-value","Is Java pass-by-value or pass-by-reference?","Java is **always pass-by-value** — no exceptions. The subtlety is that for\nobjects, the *value being copied is the reference* (the pointer), not the\nobject. So a method can **mutate** the object the reference points to, but\n**reassigning** the parameter doesn't affect the caller's variable.\n\n```java\nvoid mutate(int[] arr) { arr[0] = 99; }   \u002F\u002F changes the caller's array\nvoid reassign(int[] arr) { arr = new int[]{0}; } \u002F\u002F no effect on caller\n\nint[] a = {1};\nmutate(a);    \u002F\u002F a is now {99}\nreassign(a);  \u002F\u002F a is still {99} — the copied reference was replaced locally\n```\n\nSay it crisply in an interview: \"Java passes references **by value**.\" The\nreference is copied; both copies point at the same object until one is\nreassigned.\n",{"id":607,"difficulty":113,"q":608,"a":609},"default-values","What are the default values of fields in Java?","**Instance and static fields** are automatically initialized to a zero value:\n`0` for numeric primitives, `false` for `boolean`, `\\u0000` (the null character) for `char`, and\n**`null`** for any reference type.\n\n```java\nclass Box {\n  int n;        \u002F\u002F 0\n  boolean ok;   \u002F\u002F false\n  String name;  \u002F\u002F null\n}\n```\n\nThe crucial exception: **local variables get no default**. The compiler\n*requires* you to assign one before use, or it's a compile error (\"variable\nmight not have been initialized\") — a deliberate guard against reading garbage.\n",{"id":611,"difficulty":105,"q":612,"a":613},"int-overflow","What happens on integer overflow in Java?","Integer arithmetic **wraps around silently** using two's-complement — no\nexception is thrown. Exceeding `Integer.MAX_VALUE` rolls over to\n`Integer.MIN_VALUE`.\n\n```java\nint max = Integer.MAX_VALUE;   \u002F\u002F 2_147_483_647\nSystem.out.println(max + 1);   \u002F\u002F -2147483648  (wraps, no error)\n\n\u002F\u002F common bug: this overflows before being assigned to long\nlong bad = 1_000_000 * 1_000_000;        \u002F\u002F -727379968\nlong good = 1_000_000L * 1_000_000;      \u002F\u002F 1000000000000 (promote first)\n```\n\nMitigations: promote to `long`, use `Math.addExact`\u002F`multiplyExact` (which\n*throw* `ArithmeticException` on overflow), or `BigInteger` for unbounded math.\n",{"id":615,"difficulty":105,"q":616,"a":617},"float-precision","Why is 0.1 + 0.2 not exactly 0.3 in Java?","`float` and `double` are **binary IEEE-754** floating point. Many decimal\nfractions (like `0.1`) have no exact binary representation, so they're stored\nas the nearest approximation and tiny errors accumulate.\n\n```java\nSystem.out.println(0.1 + 0.2);   \u002F\u002F 0.30000000000000004\nSystem.out.println(0.1 + 0.2 == 0.3); \u002F\u002F false\n```\n\nFor money or anything needing exact decimals, use **`BigDecimal`** (and\nconstruct it from a *String*, not a double):\n\n```java\nnew BigDecimal(\"0.1\").add(new BigDecimal(\"0.2\")); \u002F\u002F 0.3 exactly\n```\n\nNever compare floats with `==`; compare within a small epsilon instead.\n",{"id":619,"difficulty":113,"q":620,"a":621},"char-type","What is the char type and how does it relate to int?","`char` is a **16-bit unsigned** integer holding a single UTF-16 code unit\n(`'A'`, `'7'`, `'€'`). Because it's numeric under the hood, it participates in\narithmetic and auto-promotes to `int`.\n\n```java\nchar c = 'A';\nint code = c;            \u002F\u002F 65 (implicit widening)\nchar next = (char) (c + 1); \u002F\u002F 'B' (must cast back, since c+1 is int)\nSystem.out.println('a' + 'b'); \u002F\u002F 195, not \"ab\" — numeric addition!\n```\n\nA frequent gotcha: `'a' + 'b'` adds the code points, while `\"\" + 'a' + 'b'`\nconcatenates. Characters beyond the Basic Multilingual Plane (emoji) need two\nchars (a surrogate pair) or `int` code points.\n",{"id":623,"difficulty":105,"q":624,"a":625},"casting","What is the difference between widening and narrowing conversions?","**Widening** (smaller -> larger type, e.g. `int`->`long`->`double`) is safe and\n**implicit** — no data loss, no cast needed. **Narrowing** (larger -> smaller,\ne.g. `double`->`int`) can lose data, so it requires an **explicit cast** and you\naccept the truncation.\n\n```java\nint i = 100;\nlong l = i;          \u002F\u002F widening — automatic\ndouble d = i;        \u002F\u002F widening — automatic\n\ndouble pi = 3.99;\nint n = (int) pi;    \u002F\u002F narrowing — explicit; truncates to 3 (not rounded)\nbyte b = (byte) 300; \u002F\u002F narrowing — overflows to 44\n```\n\nNarrowing **truncates toward zero** for floating->integer (it doesn't round),\nand wraps for integer overflow — both common interview \"what prints?\" traps.\n",{"id":627,"difficulty":105,"q":628,"a":629},"var-keyword","What is the var keyword and what are its limits?","`var` (Java 10+) is **local variable type inference**: the compiler infers the\nstatic type from the initializer. It's still **statically typed** — `var` is\nnot a dynamic\u002F`Object` type — just less verbose.\n\n```java\nvar list = new ArrayList\u003CString>();  \u002F\u002F inferred ArrayList\u003CString>\nvar count = 10;                      \u002F\u002F int\nfor (var entry : map.entrySet()) { } \u002F\u002F inferred Map.Entry\u003C...>\n```\n\nRestrictions: only for **local variables with an initializer**. You **can't**\nuse `var` for fields, method parameters, return types, or without an\ninitializer (`var x;` is illegal), and `var x = null;` won't compile (no type\nto infer).\n",{"id":631,"difficulty":105,"q":632,"a":633},"final-keyword","What does the final keyword mean for variables?","A `final` variable can be **assigned only once**. For a primitive that fixes\nthe value; for a reference it fixes **which object** the variable points to —\nthe object itself can still be mutated.\n\n```java\nfinal int MAX = 10;     \u002F\u002F MAX = 11; would not compile\nfinal List\u003CString> xs = new ArrayList\u003C>();\nxs.add(\"ok\");           \u002F\u002F mutating the object is allowed\nxs = new ArrayList\u003C>(); \u002F\u002F reassigning the reference is not\n```\n\n`final` also applies to fields (must be set by the end of construction),\nmethod parameters, and is required for variables a lambda\u002Fanonymous class\ncaptures (they must be `final` or *effectively final*).\n",{"id":635,"difficulty":105,"q":636,"a":637},"static-vs-instance","What is the difference between static and instance variables?","A **static** (class) variable belongs to the **class** — there's exactly **one\ncopy** shared by all instances. An **instance** variable belongs to each\n**object** — every `new` gets its own copy.\n\n```java\nclass Counter {\n  static int total;   \u002F\u002F one shared across all Counters\n  int id;             \u002F\u002F one per instance\n  Counter() { id = ++total; }\n}\nnew Counter(); \u002F\u002F id=1, total=1\nnew Counter(); \u002F\u002F id=2, total=2  (total is shared)\n```\n\nAccess statics via the class name (`Counter.total`). Statics are initialized\nwhen the class is loaded and live for the program's lifetime, which is why\nmutable static state is a common source of bugs and memory leaks.\n",{"id":639,"difficulty":113,"q":640,"a":641},"literals","How do numeric literals and underscores work in Java?","Literals default to `int` (integers) and `double` (decimals); suffixes change\nthat: `L`\u002F`l` for `long`, `f`\u002F`F` for `float`, `d`\u002F`D` for `double`. You can\nalso write binary (`0b`), octal (`0`), and hex (`0x`) literals, and use\n**underscores** as digit separators for readability.\n\n```java\nlong big   = 10_000_000_000L;  \u002F\u002F L needed — exceeds int range\nfloat rate = 1.5f;\nint  mask  = 0xFF;             \u002F\u002F 255 in hex\nint  bits  = 0b1010;           \u002F\u002F 10 in binary\nint  million = 1_000_000;      \u002F\u002F underscores ignored by the compiler\n```\n\nForgetting the `L` on a large literal is a classic bug: `10_000_000_000` alone\nwon't compile because it overflows `int`.\n",{"id":643,"difficulty":113,"q":644,"a":645},"ternary","What is the ternary operator and a common pitfall with it?","The ternary `condition ? a : b` is an **expression** that evaluates to `a` when\nthe condition is true, else `b` — a compact `if\u002Felse` that returns a value.\n\n```java\nString label = (n % 2 == 0) ? \"even\" : \"odd\";\nint max = (a > b) ? a : b;\n```\n\nThe subtle trap is **type promotion \u002F unboxing** of the two branches: if one\nbranch is a primitive and the other a wrapper, the result is unboxed, so a\n`null` wrapper branch can throw `NullPointerException`:\n\n```java\nInteger x = null;\nObject o = true ? 0 : x;   \u002F\u002F fine\nint bad  = false ? 0 : x;  \u002F\u002F NPE — both branches unboxed to int\n```\n",{"id":647,"difficulty":113,"q":648,"a":649},"arrays-basics","How are arrays represented in Java?","An array is an **object** on the heap with a fixed length set at creation; the\nvariable holds a reference to it. Elements are stored contiguously and default\nto their zero value (`0`\u002F`false`\u002F`null`).\n\n```java\nint[] a = new int[3];        \u002F\u002F {0, 0, 0}\nint[] b = {1, 2, 3};         \u002F\u002F array initializer\nString[] names = new String[2]; \u002F\u002F {null, null}\nSystem.out.println(a.length);   \u002F\u002F 3 — a field, not a method\n```\n\nKey facts: `length` is a **field** (no parentheses), the size is **immutable**\nonce created (need a bigger array? allocate a new one or use `ArrayList`), and\nout-of-bounds access throws `ArrayIndexOutOfBoundsException`.\n",{"id":651,"difficulty":105,"q":652,"a":653},"multidim-arrays","How do multidimensional and jagged arrays work?","Java has no true 2D arrays — a `int[][]` is an **array of arrays**. That means\nrows can have different lengths (a **jagged** array), and each row is a separate\nheap object.\n\n```java\nint[][] grid = new int[2][3];   \u002F\u002F 2 rows, 3 cols each\ngrid[0][1] = 5;\n\nint[][] jagged = new int[2][];  \u002F\u002F rows allocated separately\njagged[0] = new int[]{1, 2};\njagged[1] = new int[]{3, 4, 5}; \u002F\u002F different length — legal\n```\n\nBecause rows are independent objects, iterating with `row.length` (not a fixed\ncolumn count) is the safe pattern.\n",{"id":655,"difficulty":105,"q":656,"a":657},"type-promotion","How does numeric promotion work in arithmetic expressions?","In arithmetic, operands smaller than `int` (`byte`, `short`, `char`) are first\n**promoted to `int`**, and if any operand is `long`\u002F`float`\u002F`double` the whole\nexpression is promoted to the widest type. This is why byte arithmetic returns\nan `int`.\n\n```java\nbyte a = 10, b = 20;\nbyte c = a + b;        \u002F\u002F won't compile — a + b is int\nbyte d = (byte)(a + b); \u002F\u002F cast back\n\nint i = 5;\ndouble e = i \u002F 2;      \u002F\u002F 2.0 — int division happens FIRST, then widens\ndouble f = i \u002F 2.0;    \u002F\u002F 2.5 — one double operand promotes the division\n```\n\nThe `5 \u002F 2 == 2` integer-division surprise is the most common version of this\nin interviews.\n",{"id":659,"difficulty":113,"q":660,"a":661},"null-keyword","What is null and what can and cannot be null in Java?","`null` is a special literal meaning a reference points to **no object**. Only\n**reference types** can be `null` — primitives cannot. Using a `null` reference\n(calling a method, accessing a field, unboxing) throws **`NullPointerException`**.\n\n```java\nString s = null;\ns.length();          \u002F\u002F NullPointerException\nint[] a = null;\nint n = a.length;    \u002F\u002F NPE\nInteger boxed = null;\nint x = boxed;       \u002F\u002F NPE — unboxing null\n```\n\n`null` is the same regardless of type, and `instanceof` on `null` is always\n`false`. Modern Java offers `Optional` and (Java 14+) **helpful NPE messages**\nthat name the exact variable that was null.\n",{"id":663,"difficulty":105,"q":664,"a":665},"object-class","What methods does every object inherit from Object?","Every class implicitly extends `java.lang.Object`, inheriting:\n\n- `equals(Object)` — logical equality (default: reference identity).\n- `hashCode()` — int hash, must be consistent with `equals`.\n- `toString()` — string form (default: `ClassName@hexHash`).\n- `getClass()` — runtime class object.\n- `clone()` — shallow copy (protected; needs `Cloneable`).\n- `wait()\u002Fnotify()\u002FnotifyAll()` — thread coordination on the object's monitor.\n- `finalize()` — deprecated cleanup hook.\n\n```java\nclass Point {\n  int x, y;\n  @Override public String toString() { return \"(\" + x + \",\" + y + \")\"; }\n}\n```\n\nYou'll most often override `equals`, `hashCode`, and `toString` — and the\nfirst two must be overridden **together** to honor their contract.\n",{"id":667,"difficulty":113,"q":668,"a":669},"scope-block","What is variable scope in Java?","A variable is visible only within the **block (`{ }`) it's declared in**, and\nceases to exist when that block ends. Inner blocks can see outer variables, but\nnot vice versa, and you can't redeclare a name that's already in scope.\n\n```java\nvoid m() {\n  int x = 1;\n  if (x > 0) {\n    int y = 2;        \u002F\u002F visible only inside this if\n    System.out.println(x + y);\n  }\n  \u002F\u002F y is out of scope here\n}\n```\n\nLoop variables (`for (int i ...)`) are scoped to the loop. Unlike fields, local\nvariables have **no default** and must be assigned before use.\n",{"id":671,"difficulty":105,"q":672,"a":673},"implicit-explicit-cast","When do you need an explicit cast for reference types?","Assigning a subclass reference to a superclass variable (**upcasting**) is\nimplicit and always safe. Going the other way (**downcasting**) needs an\nexplicit cast *and* is checked at runtime — a wrong cast throws\n`ClassCastException`.\n\n```java\nObject o = \"hello\";          \u002F\u002F upcast — implicit\nString s = (String) o;       \u002F\u002F downcast — explicit, succeeds\nInteger bad = (Integer) o;   \u002F\u002F compiles, but throws ClassCastException\n\nif (o instanceof String str) \u002F\u002F pattern matching (Java 16+) guards the cast\n    System.out.println(str.length());\n```\n\nGuard downcasts with `instanceof` (ideally the pattern form) to avoid runtime\nfailures.\n",{"id":675,"difficulty":113,"q":676,"a":677},"constants","How do you define a constant in Java?","The idiom is **`static final`** with an UPPER_SNAKE_CASE name. `static` means\none shared copy; `final` means it can't be reassigned. The compiler can inline\n`static final` primitive\u002F`String` constants for efficiency.\n\n```java\npublic class Config {\n  public static final int MAX_RETRIES = 3;\n  public static final String APP_NAME = \"Interviews\";\n}\n```\n\nNote `final` on a reference constant only freezes the reference, not the\nobject — `static final List\u003CString> X = new ArrayList\u003C>()` can still be mutated,\nso use `List.of(...)` or `Collections.unmodifiableList` for a truly constant\ncollection.\n",{"id":679,"difficulty":113,"q":680,"a":681},"wrapper-parsing","How do you convert between Strings and numbers?","Use the wrapper classes' static methods. `parseXxx` returns a **primitive**;\n`valueOf` returns a **wrapper object**. Going the other way, `String.valueOf`\nor concatenation produces text.\n\n```java\nint n      = Integer.parseInt(\"42\");     \u002F\u002F primitive int\nInteger w  = Integer.valueOf(\"42\");       \u002F\u002F Integer object\ndouble d   = Double.parseDouble(\"3.14\");\nString s   = String.valueOf(42);          \u002F\u002F \"42\"\nString s2  = \"\" + 42;                      \u002F\u002F \"42\" (concatenation)\n```\n\nA malformed string throws **`NumberFormatException`**, so wrap parsing of\nuntrusted input in a try\u002Fcatch or validate first.\n",{"id":683,"difficulty":105,"q":684,"a":685},"bitwise","What are the bitwise and shift operators in Java?","Java has `&` (AND), `|` (OR), `^` (XOR), `~` (NOT), and shifts `\u003C\u003C`, `>>`\n(signed\u002Farithmetic right shift), and `>>>` (unsigned\u002Flogical right shift, which\nfills with zeros).\n\n```java\n5 & 3    \u002F\u002F 1   (0101 & 0011)\n5 | 3    \u002F\u002F 7\n5 ^ 3    \u002F\u002F 6\n1 \u003C\u003C 4   \u002F\u002F 16  (multiply by 2^4)\n-8 >> 1  \u002F\u002F -4  (sign-preserving)\n-8 >>> 28 \u002F\u002F 15 (zero-filled — treats bits as unsigned)\n```\n\n`>>>` is unique to Java (no unsigned types) and is the trap: it's the only shift\nthat ignores the sign bit. Bitwise `&`\u002F`|` also work on `boolean` as\nnon-short-circuiting logical operators.\n",{"id":687,"difficulty":113,"q":688,"a":689},"enhanced-for","What is the enhanced for loop and its limitations?","The enhanced for (for-each) iterates any array or `Iterable` without an index,\nreading each element in turn.\n\n```java\nfor (String name : names) {\n  System.out.println(name);\n}\n```\n\nIts limits, often asked about: you **can't get the index**, you can't iterate\ntwo collections in lockstep, and you **can't modify the collection** during\niteration (it uses an iterator under the hood, so adding\u002Fremoving throws\n`ConcurrentModificationException`). Reassigning the loop variable also doesn't\nchange the underlying element — use a classic indexed `for` or an explicit\n`Iterator` for those cases.\n",{"id":691,"difficulty":113,"q":692,"a":693},"ternary-vs-if","What is the difference between an expression and a statement?","An **expression** evaluates to a value (`a + b`, `x > 0`, `obj.method()`); a\n**statement** is a complete instruction that performs an action (`if`, `for`,\nassignments, `return`). Expressions can be nested inside statements.\n\n```java\nint max = (a > b) ? a : b;   \u002F\u002F ternary is an EXPRESSION (has a value)\nif (a > b) { max = a; }      \u002F\u002F if is a STATEMENT (no value)\n```\n\nThis distinction explains why you can write `int x = a > b ? a : b;` but not\n`int x = if (...) ...;` — `if` produces no value. (Java's `switch` gained an\n*expression* form in Java 14 that does yield a value.)\n",{"id":695,"difficulty":113,"q":696,"a":697},"text-blocks","What are text blocks in Java?","Text blocks (Java 15+) are multi-line string literals delimited by triple\nquotes `\"\"\"`. They preserve line breaks and let you write JSON, SQL, or HTML\nwithout escaping quotes or concatenating lines.\n\n```java\nString json = \"\"\"\n    {\n      \"name\": \"Ada\",\n      \"role\": \"engineer\"\n    }\n    \"\"\";\n```\n\nIncidental leading whitespace is stripped based on the closing delimiter's\nindentation, and the result is just a normal `String` — so it still goes\nthrough the pool and supports all `String` methods.\n",{"id":699,"difficulty":113,"q":700,"a":701},"identifier-rules","What are the rules for valid Java identifiers?","An identifier may contain letters, digits, `_`, and `$`, but **can't start with\na digit**, can't be a **reserved keyword** (`class`, `int`, `for`…), and is\n**case-sensitive** (`count` ≠ `Count`). Unicode letters are allowed.\n\n```java\nint count, _total, $price, αβγ;  \u002F\u002F all legal\nint 2fast;   \u002F\u002F can't start with a digit\nint class;   \u002F\u002F reserved keyword\n```\n\nBy convention (not enforced): `camelCase` for variables\u002Fmethods,\n`PascalCase` for types, `UPPER_SNAKE_CASE` for constants, and `$` is left for\ngenerated code.\n",{"description":103},"Java data types and variables interview questions — primitives vs wrappers, autoboxing, Integer caching, String immutability and the pool, pass-by-value, casting and the var keyword.","java\u002Ffundamentals\u002Fdata-types-variables","Data Types & Variables","bg3-cfmaIqX2KNq42yfDuqisehvg1EGXa9MR9I4Swks",{"id":708,"title":709,"body":710,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":714,"navigation":108,"order":13,"path":715,"questions":716,"questionsCount":805,"related":250,"seo":806,"seoDescription":807,"stem":808,"subtopic":709,"topic":37,"topicSlug":39,"updated":809,"__hash__":810},"qa\u002Fjava\u002Fgenerics\u002Fgenerics-basics.md","Generics Basics",{"type":100,"value":711,"toc":712},[],{"title":103,"searchDepth":29,"depth":29,"links":713},[],{},"\u002Fjava\u002Fgenerics\u002Fgenerics-basics",[717,721,725,729,733,737,741,745,749,753,757,761,765,769,773,777,781,785,789,793,797,801],{"id":718,"difficulty":113,"q":719,"a":720},"what-are-generics","What are generics and what problem do they solve?","**Generics** let you parameterize a class, interface, or method by **type**,\nso the same code works for many types while the compiler still enforces type\nsafety. The two big wins are **compile-time type checking** (a wrong type is a\nbuild error, not a runtime crash) and **no manual casts** when you read values\nback out.\n\n```java\nList\u003CString> names = new ArrayList\u003C>();\nnames.add(\"Ada\");\nnames.add(42);            \u002F\u002F compile error — caught early\nString n = names.get(0);  \u002F\u002F no cast needed; compiler knows it's a String\n```\n\nBefore generics (Java 5), collections held raw `Object`, so you cast on every\n`get` and a wrong type blew up at runtime with `ClassCastException`. Generics\nmove that failure to **compile time**.\n",{"id":722,"difficulty":113,"q":723,"a":724},"generic-class","How do you declare a generic class?","You add a **type parameter** in angle brackets after the class name; that\nparameter then stands in for a real type everywhere inside the class. Callers\nsupply the actual type when they create an instance.\n\n```java\nclass Box\u003CT> {            \u002F\u002F T is the type parameter\n  private T value;\n  public void set(T v) { value = v; }\n  public T get() { return value; }\n}\n\nBox\u003CString> b = new Box\u003C>();\nb.set(\"hi\");\nString s = b.get();       \u002F\u002F returns T = String, no cast\n```\n\nThe type argument (`String`) replaces `T` for that instance, so the compiler\nrejects `b.set(42)` and lets `get()` return a `String` directly.\n",{"id":726,"difficulty":113,"q":727,"a":728},"type-parameter-naming","What are the conventional names for type parameters?","Type parameters are **single uppercase letters** by convention, each hinting at\na role:\n\n| Letter | Meaning |\n| ------ | ------- |\n| `T` | Type (the generic default) |\n| `E` | Element (used by collections) |\n| `K` | Key (maps) |\n| `V` | Value (maps) |\n| `N` | Number |\n| `R` | Return type (functional interfaces) |\n| `S`, `U` | second\u002Fthird types when more are needed |\n\n```java\ninterface Map\u003CK, V> { V get(K key); }   \u002F\u002F K = key, V = value\n```\n\nThese are pure convention — the compiler accepts any valid identifier — but\nfollowing them makes generic signatures instantly readable to other developers.\n",{"id":730,"difficulty":105,"q":731,"a":732},"generic-method","What is a generic method and how do you declare one?","A **generic method** declares its **own** type parameter, written before the\nreturn type. It can appear in any class (generic or not), and the type is scoped\nto that single method.\n\n```java\n\u002F\u002F \u003CT> introduces the type parameter for this method only\nstatic \u003CT> T firstOrNull(List\u003CT> list) {\n  return list.isEmpty() ? null : list.get(0);\n}\n\nString s = firstOrNull(List.of(\"a\", \"b\")); \u002F\u002F T inferred as String\nInteger n = firstOrNull(List.\u003CInteger>of()); \u002F\u002F T = Integer\n```\n\nThe `\u003CT>` between the modifiers and the return type is what makes it generic —\nwithout it, `T` would be an undefined symbol. The method's type parameter is\nindependent of any type parameter on the enclosing class.\n",{"id":734,"difficulty":105,"q":735,"a":736},"type-inference","How does the compiler infer type arguments for a generic method?","The compiler performs **type inference**: it looks at the **argument types** and\nthe **target type** (what the result is assigned to) to deduce the type\nparameter, so you rarely write it explicitly.\n\n```java\nstatic \u003CT> List\u003CT> singleton(T item) { return List.of(item); }\n\nvar xs = singleton(\"hi\");      \u002F\u002F T inferred from \"hi\" -> String\nList\u003CInteger> ys = singleton(7); \u002F\u002F T inferred -> Integer\n```\n\nWhen inference can't decide (or you want to override it), supply an **explicit\ntype witness** before the method name: `Collections.\u003CString>emptyList()`. This is\noccasionally needed when there are no arguments to infer from.\n",{"id":738,"difficulty":113,"q":739,"a":740},"diamond-operator","What is the diamond operator?","The **diamond operator** `\u003C>` (Java 7+) lets you omit the type arguments on the\nright side of an assignment; the compiler infers them from the **declared type**\non the left (the target type).\n\n```java\n\u002F\u002F verbose, pre-Java 7\nMap\u003CString, List\u003CInteger>> m = new HashMap\u003CString, List\u003CInteger>>();\n\n\u002F\u002F diamond — compiler infers \u003CString, List\u003CInteger>>\nMap\u003CString, List\u003CInteger>> m2 = new HashMap\u003C>();\n```\n\nIt cuts redundant boilerplate without losing any type safety — `new HashMap\u003C>()`\nis still fully generic, just inferred. Note `new HashMap()` (no diamond) is a\n**raw type** and is *not* the same thing.\n",{"id":742,"difficulty":113,"q":743,"a":744},"generic-interface","How do you define and implement a generic interface?","A generic interface declares type parameters just like a class. An implementor\neither **fixes** the type or **stays generic** by passing its own parameter\nthrough.\n\n```java\ninterface Repository\u003CT> {\n  void save(T item);\n  T findById(int id);\n}\n\n\u002F\u002F fix the type\nclass UserRepo implements Repository\u003CUser> {\n  public void save(User u) { }\n  public User findById(int id) { return null; }\n}\n\n\u002F\u002F stay generic\nclass MemRepo\u003CT> implements Repository\u003CT> { \u002F* ... *\u002F }\n```\n\nCore JDK interfaces like `Comparable\u003CT>`, `Iterable\u003CE>`, and `Comparator\u003CT>` work\nthis way, which is why `class Money implements Comparable\u003CMoney>` gives you a\ntype-safe `compareTo(Money)`.\n",{"id":746,"difficulty":113,"q":747,"a":748},"multiple-type-parameters","Can a generic type have more than one type parameter?","Yes — list them comma-separated inside the angle brackets. The classic example\nis `Map\u003CK, V>`, which is parameterized by both a **key** type and a **value**\ntype.\n\n```java\nclass Pair\u003CA, B> {\n  final A first;\n  final B second;\n  Pair(A a, B b) { first = a; second = b; }\n}\n\nPair\u003CString, Integer> p = new Pair\u003C>(\"age\", 30);\nString key = p.first;   \u002F\u002F A = String\nint val = p.second;     \u002F\u002F B = Integer\n```\n\nEach parameter is independent, so `Pair\u003CString, Integer>` and\n`Pair\u003CInteger, String>` are distinct, incompatible types.\n",{"id":750,"difficulty":105,"q":751,"a":752},"type-safety","How do generics improve type safety over Object?","Without generics you'd store everything as `Object`, deferring all type checking\nto **runtime casts** that can fail. Generics let the **compiler** verify types,\nturning a potential `ClassCastException` into a build error.\n\n```java\n\u002F\u002F pre-generics style\nList raw = new ArrayList();\nraw.add(\"hi\");\nInteger n = (Integer) raw.get(0);  \u002F\u002F compiles, ClassCastException at runtime\n\n\u002F\u002F generic style\nList\u003CString> safe = new ArrayList\u003C>();\nsafe.add(\"hi\");\nInteger m = safe.get(0);           \u002F\u002F compile error — caught immediately\n```\n\nThe cast disappears because the compiler already knows the element type, and it\ninserts any needed cast for you behind the scenes.\n",{"id":754,"difficulty":105,"q":755,"a":756},"raw-types","What is a raw type and why is it discouraged?","A **raw type** is a generic type used **without** its type argument, e.g. `List`\ninstead of `List\u003CString>`. It exists only for **backward compatibility** with\npre-Java-5 code, and using it **opts out of type safety** — the compiler can no\nlonger check element types.\n\n```java\nList raw = new ArrayList();   \u002F\u002F raw type\nraw.add(\"hi\");\nraw.add(42);                  \u002F\u002F no complaint — types unchecked\nString s = (String) raw.get(1); \u002F\u002F ClassCastException at runtime\n```\n\nRaw types produce **unchecked warnings** and re-introduce exactly the runtime\nfailures generics were designed to prevent. Always parameterize — use\n`List\u003CObject>` if you genuinely want any type, which keeps checking on.\n",{"id":758,"difficulty":126,"q":759,"a":760},"raw-vs-object","What is the difference between List, List\u003CObject>, and List\u003C?>?","They look similar but behave very differently:\n\n| Type | Meaning | Type-checked? |\n| ---- | ------- | ------------- |\n| `List` | **raw** — legacy escape hatch | No (unchecked warnings) |\n| `List\u003CObject>` | a list that can hold **any** type | Yes |\n| `List\u003C?>` | a list of some **unknown** type | Yes (read-only) |\n\n```java\nList\u003CString> strings = new ArrayList\u003C>();\nList\u003CObject> objs = strings; \u002F\u002F compile error — not the same type\nList\u003C?> any = strings;       \u002F\u002F OK — wildcard accepts any List\u003CX>\nany.add(\"x\");                \u002F\u002F error — can't add to List\u003C?> (type unknown)\n```\n\nThe key trap: `List\u003CObject>` is **not** a supertype of `List\u003CString>` (generics\nare invariant), so you can't assign one to the other — that's where wildcards\ncome in.\n",{"id":762,"difficulty":126,"q":763,"a":764},"cannot-instantiate-type","Why can't you write new T() inside a generic class?","Because of **type erasure**, the type parameter `T` doesn't exist at runtime —\nthe JVM has no idea what concrete class to instantiate, so `new T()` is a compile\nerror. There's no constructor to call when `T` is unknown.\n\n```java\nclass Factory\u003CT> {\n  T create() {\n    return new T();          \u002F\u002F compile error — cannot instantiate T\n  }\n}\n```\n\nThe standard workaround is to pass a factory or a `Class\u003CT>` token and use\nreflection:\n\n```java\nT create(Class\u003CT> type) throws Exception {\n  return type.getDeclaredConstructor().newInstance();\n}\n```\n\n(Erasure has its own page — here it's enough to know `T` isn't a real runtime\ntype.)\n",{"id":766,"difficulty":126,"q":767,"a":768},"cannot-create-generic-array","Why can't you create a generic array like new T[]?","Arrays are **reified** — they know and check their element type at runtime —\nwhile generics are **erased**. Mixing the two would let an unchecked store slip\nthrough, so the compiler forbids `new T[]` and `new List\u003CString>[]`.\n\n```java\nclass Stack\u003CT> {\n  \u002F\u002F T[] data = new T[10];        \u002F\u002F compile error — generic array creation\n  Object[] data = new Object[10];  \u002F\u002F workaround: store as Object[]\n  @SuppressWarnings(\"unchecked\")\n  T get(int i) { return (T) data[i]; } \u002F\u002F cast on read\n}\n```\n\nThe common pattern is an `Object[]` backing store with a suppressed cast on\nread, which is exactly how `ArrayList` is implemented internally.\n",{"id":770,"difficulty":126,"q":771,"a":772},"generics-invariance","Why is List\u003CString> not a List\u003CObject>?","Generics are **invariant**: even though `String` is a subtype of `Object`,\n`List\u003CString>` is **not** a subtype of `List\u003CObject>`. If it were, you could\nbreak type safety by adding the wrong type through the supertype reference.\n\n```java\nList\u003CString> strings = new ArrayList\u003C>();\nList\u003CObject> objs = strings;   \u002F\u002F suppose this were allowed...\nobjs.add(42);                  \u002F\u002F ...then this would put an Integer in\nString s = strings.get(0);     \u002F\u002F ...and this would explode at runtime\n```\n\nThe compiler blocks the assignment to keep that from ever happening. Arrays, by\ncontrast, *are* covariant (`String[]` is an `Object[]`), which is exactly why\narray stores are checked at runtime and can throw `ArrayStoreException`.\n",{"id":774,"difficulty":105,"q":775,"a":776},"bounded-type-parameter","What is a bounded type parameter?","A **bound** restricts what types a parameter accepts using `extends`. `\u003CT extends\nNumber>` means \"any `T` that is `Number` or a subclass,\" which lets you call that\nbound's methods on `T`.\n\n```java\n\u002F\u002F T must be a Number, so .doubleValue() is available\nstatic \u003CT extends Number> double sum(List\u003CT> nums) {\n  double total = 0;\n  for (T n : nums) total += n.doubleValue();\n  return total;\n}\n\nsum(List.of(1, 2, 3));       \u002F\u002F OK — Integer extends Number\nsum(List.of(\"a\", \"b\"));      \u002F\u002F compile error — String isn't a Number\n```\n\n`extends` works for both classes and interfaces here, and you can require several\nbounds with `&` (`\u003CT extends Number & Comparable\u003CT>>`). Wildcards and more\nadvanced bounding are covered on the wildcards page.\n",{"id":778,"difficulty":105,"q":779,"a":780},"suppress-warnings-unchecked","When and how do you use @SuppressWarnings(\"unchecked\")?","`@SuppressWarnings(\"unchecked\")` silences the compiler's **unchecked** warnings —\nthe ones emitted when you do a cast or operation the compiler can't fully verify\nbecause of erasure. Use it only when you've **reasoned that the cast is safe**.\n\n```java\n@SuppressWarnings(\"unchecked\")           \u002F\u002F safe: we only ever store T here\nT get(int i) { return (T) data[i]; }\n```\n\nBest practice: put it on the **narrowest scope possible** (a single local\nvariable or method, never a whole class), and add a comment explaining why the\noperation is actually safe. Suppressing warnings blindly hides real bugs.\n",{"id":782,"difficulty":105,"q":783,"a":784},"var-with-generics","How does var interact with generics?","`var` infers the **full generic type** from the initializer, so you keep complete\ntype safety without repeating long parameter lists. But the initializer must\ncarry the type information — a bare diamond gives `var` nothing to infer.\n\n```java\nvar users = new HashMap\u003CString, List\u003CUser>>(); \u002F\u002F inferred fully\nvar first = users.get(\"a\");                     \u002F\u002F List\u003CUser>\n\nvar bad = new ArrayList\u003C>();   \u002F\u002F infers ArrayList\u003CObject> — probably not wanted\n```\n\nWith `var` the **right-hand side must specify the type arguments** (the diamond\ncan't borrow them from a left-hand declaration that no longer exists). So write\n`new ArrayList\u003CString>()`, not `new ArrayList\u003C>()`, when using `var`.\n",{"id":786,"difficulty":126,"q":787,"a":788},"generic-constructor","Can a constructor have its own type parameter?","Yes — a constructor can declare type parameters **independent** of the class's\nown, written before the constructor name. This is rare but valid when the\nconstructor needs a type only for its arguments.\n\n```java\nclass Holder\u003CT> {\n  private T value;\n  \u002F\u002F S is the constructor's own parameter, separate from class T\n  \u003CS extends T> Holder(S initial) {\n    this.value = initial;\n  }\n}\n```\n\nHere `S` is scoped to the constructor; the class is still `Holder\u003CT>`. Most code\njust reuses the class's `T`, but a generic constructor lets you accept a more\nspecific or unrelated type for construction only.\n",{"id":790,"difficulty":126,"q":791,"a":792},"static-generic-method","Why must a static method declare its own type parameter?","A static method belongs to the **class, not an instance**, so it **can't see the\nclass's type parameter** — that parameter only exists per object. A static method\nthat needs generics must declare its **own**.\n\n```java\nclass Box\u003CT> {\n  T value;\n  \u002F\u002F static \u003CT> needed — the class's T is not in scope here\n  static \u003CU> Box\u003CU> of(U v) {\n    Box\u003CU> b = new Box\u003C>();\n    b.value = v;\n    return b;\n  }\n}\n\nBox\u003CString> b = Box.of(\"hi\");   \u002F\u002F U inferred as String\n```\n\nUsing the class's `T` in a static method is a compile error precisely because\nthere's no instance to bind it to. (Naming the static parameter the same letter\nas the class's is legal but confusing — use a different letter.)\n",{"id":794,"difficulty":105,"q":795,"a":796},"generics-vs-erasure","At a high level, how do generics exist at runtime?","Java generics are a **compile-time** feature implemented by **type erasure**:\nthe compiler checks types and inserts casts, then **removes** the type\nparameters so the bytecode works on `Object` (or the bound). At runtime, a\n`List\u003CString>` and a `List\u003CInteger>` are just `List`.\n\n```java\nList\u003CString> a = new ArrayList\u003C>();\nList\u003CInteger> b = new ArrayList\u003C>();\nSystem.out.println(a.getClass() == b.getClass()); \u002F\u002F true — both ArrayList\n```\n\nThe benefit is **backward compatibility** with pre-generics bytecode; the cost\nis that types aren't available for reflection or runtime checks. The full\nmechanics and consequences live on the type-erasure page.\n",{"id":798,"difficulty":105,"q":799,"a":800},"why-not-primitives","Why can't you use primitives as type arguments?","Because of erasure, type parameters become `Object` at runtime, and primitives\naren't objects — so `List\u003Cint>` is illegal. You must use the **wrapper class**\n(`Integer`, `Double`, …), and autoboxing bridges the gap.\n\n```java\nList\u003Cint> nums;            \u002F\u002F compile error\nList\u003CInteger> nums2 = new ArrayList\u003C>();\nnums2.add(5);              \u002F\u002F autoboxed int -> Integer\nint x = nums2.get(0);      \u002F\u002F unboxed Integer -> int\n```\n\nThe trade-off is **boxing overhead** for large numeric collections, which is why\nspecialized primitive streams (`IntStream`) and libraries with primitive\ncollections exist. Project Valhalla aims to relax this in the future.\n",{"id":802,"difficulty":105,"q":803,"a":804},"comparable-generic","How does the Comparable\u003CT> interface use generics?","`Comparable\u003CT>` is generic so `compareTo` takes a **typed** argument instead of\nraw `Object` — no cast, and you can't accidentally compare against the wrong\ntype. You parameterize it with **your own class**.\n\n```java\nclass Version implements Comparable\u003CVersion> {\n  int number;\n  \u002F\u002F typed parameter — no casting from Object\n  public int compareTo(Version other) {\n    return Integer.compare(this.number, other.number);\n  }\n}\n```\n\nCompare this to the legacy raw `Comparable`, where `compareTo(Object o)` forced a\ndowncast. Bounding on `Comparable` (`\u003CT extends Comparable\u003CT>>`) is also how\nmethods like `Collections.max` guarantee their elements are orderable.\n",22,{"description":103},"Java generics interview questions — what generics are and why, generic classes and methods, type parameters, the diamond operator, type safety, raw types, and generic constructors.","java\u002Fgenerics\u002Fgenerics-basics","2026-06-20","RZvplRmyNsoceXctYSH0TDs9i3Jrl9pRwiY6A4Jnbjk",{"id":812,"title":813,"body":814,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":818,"navigation":108,"order":13,"path":819,"questions":820,"questionsCount":904,"related":250,"seo":905,"seoDescription":906,"stem":907,"subtopic":908,"topic":81,"topicSlug":83,"updated":809,"__hash__":909},"qa\u002Fjava\u002Fjvm-internals\u002Fmemory-heap-stack.md","Memory Heap Stack",{"type":100,"value":815,"toc":816},[],{"title":103,"searchDepth":29,"depth":29,"links":817},[],{},"\u002Fjava\u002Fjvm-internals\u002Fmemory-heap-stack",[821,825,829,833,837,841,845,849,853,857,861,865,869,872,876,880,884,888,892,896,900],{"id":822,"difficulty":113,"q":823,"a":824},"heap-vs-stack","What is the difference between the heap and the stack in the JVM?","The **stack** is a per-thread memory region that stores **stack frames** —\nlocal variables, method parameters, and return addresses for each active\nmethod call. It is **LIFO** and automatically reclaimed when a frame pops.\nThe **heap** is shared across all threads and holds every **object instance**\nand every **array** created with `new`.\n\n```java\nvoid demo() {\n    int x = 42;                \u002F\u002F x lives on the stack (primitive local)\n    String s = new String(\"hi\"); \u002F\u002F the String object lives on the heap;\n                                 \u002F\u002F s (the reference) lives on the stack\n}\n```\n\n**Rule of thumb:** if it was created with `new`, it's on the heap; local\nprimitives and references themselves live on the stack.\n",{"id":826,"difficulty":113,"q":827,"a":828},"what-lives-on-stack","What exactly is stored on the stack for each method call?","Each method invocation creates a **stack frame** containing:\n- **Local variable array** — method parameters and `local` variables\n  (primitives stored by value, object references stored as pointers).\n- **Operand stack** — a work area the JVM uses to execute bytecode\n  instructions (push, pop, arithmetic).\n- **Frame data** — a reference to the runtime constant pool entry for the\n  current class and the return address.\n\n```java\nint add(int a, int b) {   \u002F\u002F a and b are in the local variable array\n    int sum = a + b;      \u002F\u002F sum is also in the local variable array\n    return sum;           \u002F\u002F frame pops; sum is gone\n}\n```\n\n**Rule of thumb:** the stack frame is the method's private scratch pad —\nit is created on call and destroyed on return.\n",{"id":830,"difficulty":113,"q":831,"a":832},"object-reference-on-stack","Does an object reference live on the stack or the heap?","The **reference variable** (the pointer) lives on the stack (or as a field\ninside another heap object), while the **object it points to** always lives\non the heap.\n\n```java\nvoid foo() {\n    StringBuilder sb = new StringBuilder(); \u002F\u002F ref 'sb' is on the stack;\n                                            \u002F\u002F the StringBuilder is on the heap\n    sb.append(\"hi\");\n}   \u002F\u002F frame pops → 'sb' gone; object may be GC'd if no other references\n```\n\n**Rule of thumb:** never confuse the address with the house — the reference\nis the address card, the object is the house.\n",{"id":834,"difficulty":105,"q":835,"a":836},"heap-regions","How is the Java heap divided internally?","The HotSpot heap uses a **generational** layout for the default GC collectors:\n\n| Region | Purpose |\n|---|---|\n| **Eden** | new objects allocated here first |\n| **Survivor 0 \u002F S1** | objects that survived one GC cycle |\n| **Old Gen (Tenured)** | long-lived objects promoted from Young Gen |\n\nEden + Survivor spaces together form the **Young Generation**. A\n**Minor GC** collects Young Gen; a **Major\u002FFull GC** also collects Old Gen.\n\n```java\n\u002F\u002F From the JVM perspective:\n\u002F\u002F new Object() → allocated in Eden\n\u002F\u002F survives N minor GCs → copied to Survivor space\n\u002F\u002F reaches tenure threshold → promoted to Old Gen\n```\n\n**Rule of thumb:** short-lived objects die young in Eden; objects that\nsurvive long enough are promoted to Old Gen where collection is expensive.\n",{"id":838,"difficulty":105,"q":839,"a":840},"metaspace","What is Metaspace and how does it differ from PermGen?","**PermGen** (Permanent Generation) was a fixed-size heap region in Java ≤ 7\nthat stored **class metadata**, interned strings, and static fields.\nIt was notorious for `OutOfMemoryError: PermGen space` when too many classes\nwere loaded (e.g., by hot-deploy in app servers).\n\nJava 8 replaced it with **Metaspace**, which lives in **native memory**\n(outside the Java heap) and grows dynamically by default.\n\n```\n# Java 7 and earlier:\n-XX:MaxPermSize=256m    # had to be tuned manually\n\n# Java 8+:\n-XX:MaxMetaspaceSize=256m  # optional cap; unlimited by default\n```\n\n**Rule of thumb:** Metaspace can't cause `PermGen` errors because it is not\non the heap — but without a cap it can exhaust native memory, so set\n`-XX:MaxMetaspaceSize` in long-running servers.\n",{"id":842,"difficulty":113,"q":843,"a":844},"stack-overflow-error","What causes a StackOverflowError?","Each thread has a fixed-size stack. When method calls nest too deeply —\nalmost always due to **unbounded recursion** — the stack runs out of space\nand the JVM throws `StackOverflowError`.\n\n```java\nint factorial(int n) {\n    return n * factorial(n - 1); \u002F\u002F no base case → infinite recursion\n}\n\u002F\u002F Throws: java.lang.StackOverflowError\n```\n\nThe default thread stack size is typically 512 KB – 1 MB (JVM-dependent).\nIt can be changed with `-Xss` (e.g., `-Xss2m`).\n\n**Rule of thumb:** `StackOverflowError` almost always means missing or\nincorrect base case in recursion; check the call chain, not the heap.\n",{"id":846,"difficulty":105,"q":847,"a":848},"outofmemoryerror-heap","What causes OutOfMemoryError: Java heap space?","The JVM throws `OutOfMemoryError: Java heap space` when it cannot allocate\na new object even after running GC and expanding the heap to `-Xmx`.\nCommon causes are **memory leaks** (objects retained unintentionally),\n**large data loads** (reading an entire file into memory), or a heap that\nis simply too small for the workload.\n\n```java\nList\u003Cbyte[]> leak = new ArrayList\u003C>();\nwhile (true) {\n    leak.add(new byte[1024 * 1024]); \u002F\u002F keeps reference → GC can't collect\n}\n\u002F\u002F java.lang.OutOfMemoryError: Java heap space\n```\n\nDiagnose with a heap dump (`-XX:+HeapDumpOnOutOfMemoryError`) and inspect\nwith MAT or VisualVM.\n\n**Rule of thumb:** `OOM: Java heap space` means either the heap is too\nsmall or something is holding references it shouldn't.\n",{"id":850,"difficulty":113,"q":851,"a":852},"xms-xmx","What do -Xms and -Xmx control?","`-Xms` sets the **initial heap size** and `-Xmx` sets the **maximum heap\nsize**. The JVM starts with `Xms` and grows up to `Xmx` as needed.\n\n```bash\njava -Xms512m -Xmx2g MyApp\n# starts with 512 MB heap, can grow to 2 GB\n```\n\nSetting them equal avoids heap-resize pauses in production (no\nexpansion\u002Fshrink cycles), at the cost of reserving the full memory upfront.\n\n**Rule of thumb:** in production containers set `-Xms` = `-Xmx` to keep\nheap size predictable and prevent GC-driven resize pauses.\n",{"id":854,"difficulty":126,"q":855,"a":856},"escape-analysis","What is escape analysis and how does it affect heap allocation?","**Escape analysis** is a JIT optimization where the compiler determines\nwhether an object's reference **escapes** the method or thread it was\ncreated in. If it doesn't escape, the JVM can **allocate it on the stack**\nor **scalar-replace** it (break it into individual fields), avoiding heap\nallocation and GC pressure entirely.\n\n```java\nvoid compute() {\n    Point p = new Point(1, 2); \u002F\u002F if p never escapes this method…\n    int sum = p.x + p.y;       \u002F\u002F …JIT may replace it with two int locals\n}                              \u002F\u002F no heap allocation, no GC overhead\n```\n\nEscape analysis is enabled by default in HotSpot (`-XX:+DoEscapeAnalysis`).\nIt explains why micro-benchmarks allocating temporary objects sometimes show\nsurprisingly low GC activity.\n\n**Rule of thumb:** you can't force escape analysis, but writing short-lived\nhelper objects inside a method (not passing them out) gives the JIT the best\nchance to eliminate the allocation.\n",{"id":858,"difficulty":105,"q":859,"a":860},"stack-thread-safety","Why are local variables thread-safe without synchronization?","Each thread has its **own stack**. Local variables (including primitive\nlocals and object references local to a method) exist only in that thread's\nstack frames. No other thread can see or modify them, so there is no sharing\nand no synchronization is needed.\n\n```java\nvoid process() {\n    int counter = 0;        \u002F\u002F on this thread's stack — invisible to others\n    counter++;              \u002F\u002F safe, no volatile\u002Fsynchronized needed\n}\n```\n\nObjects on the **heap**, however, can be reachable from multiple threads via\nshared references, which is where thread-safety concerns arise.\n\n**Rule of thumb:** stack data is private to its thread; only shared heap\ndata needs synchronization.\n",{"id":862,"difficulty":126,"q":863,"a":864},"object-header","What does every Java object carry in memory beyond its fields?","Every heap object has a hidden **object header** prepended by the JVM,\ntypically **16 bytes** on a 64-bit JVM (or 12 bytes with compressed oops):\n\n| Part | Size | Purpose |\n|---|---|---|\n| **Mark word** | 8 bytes | hashCode, GC age bits, lock state, biased-locking info |\n| **Class pointer** | 4–8 bytes | pointer to the class metadata in Metaspace |\n\nAfter the header come the **instance fields**, then padding to align to 8\nbytes.\n\n```java\n\u002F\u002F Rough layout of: new Object()\n\u002F\u002F [mark word 8 bytes][class ptr 4 bytes][4 bytes padding] = 16 bytes minimum\n```\n\n**Rule of thumb:** even an empty `new Object()` costs at least 16 bytes on\nheap — object count matters for memory budgets, not just field sizes.\n",{"id":866,"difficulty":105,"q":867,"a":868},"minor-vs-major-gc","What is the difference between a Minor GC and a Full GC?","A **Minor GC** (also called a Young GC) collects only the **Young\nGeneration** (Eden + Survivor spaces). It is fast because Young Gen is\nsmall and most objects there are already dead. It causes a short\n**stop-the-world** pause.\n\nA **Full GC** (or Major GC) collects the **entire heap** — Young Gen and\nOld Gen — and also processes Metaspace. It is much slower and causes a\nlonger pause. It is triggered when Old Gen fills up or when\n`System.gc()` is called.\n\n```\n\u002F\u002F Triggering a Full GC deliberately (rarely advisable in production):\nSystem.gc();  \u002F\u002F hint only; JVM may ignore it\n```\n\n**Rule of thumb:** frequent Full GCs are a red flag — they signal that\nobjects are promoted to Old Gen faster than it can be cleaned, often due\nto a memory leak or undersized heap.\n",{"id":595,"difficulty":105,"q":870,"a":871},"Where does the String pool live and how does it affect memory?","The **String pool** (interned String table) lives on the **heap** in Java 7+\n(it was in PermGen in Java 6 and earlier). String literals are automatically\ninterned; calling `String.intern()` manually adds a string to the pool.\n\n```java\nString a = \"hello\";           \u002F\u002F from the string pool\nString b = \"hello\";           \u002F\u002F same pooled object\nString c = new String(\"hello\"); \u002F\u002F new heap object, NOT pooled\nSystem.out.println(a == b);   \u002F\u002F true  — same pool reference\nSystem.out.println(a == c);   \u002F\u002F false — c is a distinct heap object\n```\n\nBecause the pool is on the heap it is subject to GC, so interned strings\nthat are no longer referenced can be collected (unlike PermGen, which was\nnever GC'd in Java 6).\n\n**Rule of thumb:** prefer `equals()` for string comparison; `==` only works\nreliably on pool references (literals or explicitly interned strings).\n",{"id":873,"difficulty":126,"q":874,"a":875},"compressed-oops","What are compressed ordinary object pointers (compressed oops)?","On a 64-bit JVM, a raw pointer to a heap object is 8 bytes. **Compressed\noops** (`-XX:+UseCompressedOops`, enabled by default when heap ≤ 32 GB)\nstore object references as **32-bit values** by encoding the pointer as a\n**word offset** (address >> 3). The JVM shifts the value back to a full\n64-bit address at use time, transparently.\n\n```\n# Enabled automatically when -Xmx \u003C= ~32 GB:\n-XX:+UseCompressedOops      # compress heap references\n-XX:+UseCompressedClassPointers  # also compress class pointers in header\n```\n\nThis reduces per-object memory by shrinking every reference field and the\nclass pointer in the header from 8 → 4 bytes, which often cuts heap usage\nby 20–30 %.\n\n**Rule of thumb:** keep heap below 32 GB to retain compressed oops; crossing\nthat boundary can actually increase memory usage because every reference\ngrows from 4 to 8 bytes.\n",{"id":877,"difficulty":126,"q":878,"a":879},"thread-local-allocation-buffer","What is a TLAB (Thread-Local Allocation Buffer)?","Allocating on the heap naively would require synchronization on every `new`\nbecause all threads share Eden. The JVM avoids this by giving each thread\nits own private chunk of Eden called a **TLAB**. Allocations within the\nthread just bump a pointer inside the TLAB — no locking needed.\n\n```\n\u002F\u002F Conceptually:\nThread T1 → has TLAB [0x1000 – 0x2000]\nThread T2 → has TLAB [0x2000 – 0x3000]\nnew Foo() in T1 → bumps T1's pointer; no synchronization\n```\n\nWhen a TLAB is exhausted the thread requests a fresh one from Eden (under a\nbrief lock). Objects too large for any TLAB are allocated directly in Eden\nor Old Gen.\n\n**Rule of thumb:** TLABs are why Java object allocation is nearly as cheap\nas incrementing a pointer — the cost shows up at GC time, not at `new`.\n",{"id":881,"difficulty":105,"q":882,"a":883},"soft-weak-phantom-references","How do soft, weak, and phantom references interact with heap memory?","Java provides reference types that let the **GC reclaim objects** under\ndifferent urgency levels, avoiding `OutOfMemoryError` for caches:\n\n| Type | Cleared when | Use case |\n|---|---|---|\n| `SoftReference\u003CT>` | GC needs memory (before OOM) | memory-sensitive caches |\n| `WeakReference\u003CT>` | next GC, regardless of memory | canonicalizing maps (`WeakHashMap`) |\n| `PhantomReference\u003CT>` | after finalization, just before reclaim | post-mortem cleanup \u002F resource release |\n\n```java\nCache\u003CK, V> cache = new LinkedHashMap\u003C>();\nSoftReference\u003CBigData> ref = new SoftReference\u003C>(loadData());\nBigData d = ref.get(); \u002F\u002F null if GC has already cleared it\n```\n\n**Rule of thumb:** use `SoftReference` for caches you want the GC to evict\nunder pressure, `WeakReference` when you don't want to prevent collection,\nand `PhantomReference` only when you need a GC notification callback.\n",{"id":885,"difficulty":105,"q":886,"a":887},"gc-roots","What are GC roots and why do they matter?","**GC roots** are the starting points from which the garbage collector traces\nlive object graphs. Any object reachable from a GC root is considered live\nand will not be collected. Common GC roots include:\n\n- Local variables and operand-stack entries in **active stack frames**\n- **Static fields** of loaded classes\n- References held by **JNI** (native code)\n- Objects referenced by **active threads** themselves\n\n```java\nstatic List\u003CObject> cache = new ArrayList\u003C>(); \u002F\u002F static field = GC root\n\u002F\u002F anything added to 'cache' will never be GC'd while the class is loaded\n```\n\nMemory leaks in Java are almost always objects that remain reachable from a\nGC root unintentionally (e.g., a static list that grows forever).\n\n**Rule of thumb:** a Java memory leak is not \"memory the GC can't see\" but\n\"memory the GC won't collect because a root still points to it.\"\n",{"id":889,"difficulty":105,"q":890,"a":891},"stack-size-tuning","When and how would you tune the thread stack size?","The default thread stack size (typically 512 KB on 64-bit Linux) is\nsufficient for most apps. You'd increase it with `-Xss` if deep but\nlegitimate recursion (e.g., recursive descent parsers, deep call chains in\nframeworks) causes `StackOverflowError`.\n\n```bash\njava -Xss2m MyApp   # 2 MB stack per thread\n```\n\nBe careful: each thread gets its own stack, so doubling `-Xss` in an app\nwith 500 threads doubles the native memory reserved for stacks. This memory\ncomes from **native (off-heap) memory**, not from the Java heap.\n\n**Rule of thumb:** increase `-Xss` only when you own the recursion and\ncan't refactor it to iteration; otherwise fix the algorithm.\n",{"id":893,"difficulty":105,"q":894,"a":895},"native-memory","What is native (off-heap) memory in the JVM and what uses it?","**Native memory** (also called off-heap memory) is memory the JVM allocates\nfrom the OS directly, outside the Java heap. It is not managed by the\ngarbage collector. Key consumers include:\n\n| Consumer | Notes |\n|---|---|\n| Thread stacks | one per thread × `-Xss` |\n| Metaspace | class metadata |\n| Code cache | JIT-compiled native code |\n| Direct ByteBuffers | `ByteBuffer.allocateDirect()` |\n| GC data structures | card tables, remembered sets |\n\n```java\nByteBuffer buf = ByteBuffer.allocateDirect(64 * 1024 * 1024); \u002F\u002F 64 MB off-heap\n\u002F\u002F not counted in -Xmx, freed when buf is GC'd or explicitly with Cleaner\n```\n\n**Rule of thumb:** if a process's RSS grows well beyond `-Xmx`, the culprit\nis usually native memory — Metaspace, thread stacks, or direct buffers.\n",{"id":897,"difficulty":105,"q":898,"a":899},"heap-dump-analysis","How do you take and analyze a heap dump to diagnose a memory leak?","Capture a heap dump while the leak is active, then inspect it with a tool\nlike Eclipse MAT or VisualVM to find the **dominator tree** — the objects\nretaining the most memory.\n\n```bash\n# Enable automatic dump on OOM:\njava -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\u002Ftmp\u002Fdump.hprof MyApp\n\n# Manual dump of running process (PID 12345):\njmap -dump:live,format=b,file=\u002Ftmp\u002Fdump.hprof 12345\n```\n\nIn MAT, the **\"Leak Suspects\" report** identifies objects accumulating in\nmemory and traces the shortest path back to a GC root — that path reveals\nwhy the object isn't being collected.\n\n**Rule of thumb:** always capture the heap dump while the problem is\noccurring; a dump taken after a restart won't show the leaked objects.\n",{"id":901,"difficulty":105,"q":902,"a":903},"generational-hypothesis","What is the weak generational hypothesis and why does it guide GC design?","The **weak generational hypothesis** is the empirical observation that\n**most objects die young** — they are allocated, used briefly, and become\ngarbage within a few milliseconds. A minority of objects survive long term.\n\nThis drives the **generational GC design**: allocate cheaply in a small,\nfrequently-collected Young Gen where most objects die without ever touching\nOld Gen. Only survivors get promoted to the expensive-to-collect Old Gen.\n\n```\nTypical production allocation profile:\n  ~90 % of objects die before their first Minor GC\n  ~5–9 % get promoted after a few GC cycles\n  ~1 % live for the application's lifetime (caches, singletons)\n```\n\n**Rule of thumb:** generational GC works well when you respect the\nhypothesis — minimize long-lived object graphs and avoid putting ephemeral\nobjects in static caches.\n",21,{"description":103},"Java JVM memory interview questions — heap vs stack, stack frames, object allocation, Eden\u002FSurvivor\u002FOld Gen regions, Metaspace, escape analysis, OutOfMemoryError, and StackOverflowError.","java\u002Fjvm-internals\u002Fmemory-heap-stack","Memory — Heap & Stack","WDcFt9dt33P6sHnOxhkvhG5xvOpguKDxfTFB1GY9uCM",{"id":911,"title":912,"body":913,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":917,"navigation":108,"order":13,"path":918,"questions":919,"questionsCount":980,"related":250,"seo":981,"seoDescription":982,"stem":983,"subtopic":912,"topic":90,"topicSlug":92,"updated":809,"__hash__":984},"qa\u002Fjava\u002Fmodern-java\u002Frecords.md","Records",{"type":100,"value":914,"toc":915},[],{"title":103,"searchDepth":29,"depth":29,"links":916},[],{},"\u002Fjava\u002Fmodern-java\u002Frecords",[920,924,928,932,936,940,944,948,952,956,960,964,968,972,976],{"id":921,"difficulty":113,"q":922,"a":923},"what-is-a-record","What is a record in Java and what problem does it solve?","A **record** (Java 16, JEP 395) is a special class declaration for\n**immutable data carriers**. It eliminates the boilerplate of writing\nconstructors, `equals()`, `hashCode()`, `toString()`, and accessor methods\nfor classes whose sole purpose is to hold data.\n\n```java\n\u002F\u002F Before records — ~30 lines of boilerplate:\npublic final class Point {\n    private final int x;\n    private final int y;\n    public Point(int x, int y) { this.x = x; this.y = y; }\n    public int x() { return x; }\n    public int y() { return y; }\n    @Override public boolean equals(Object o) { ... }\n    @Override public int hashCode() { ... }\n    @Override public String toString() { ... }\n}\n\n\u002F\u002F With a record — 1 line:\nrecord Point(int x, int y) {}\n```\n\n**Rule of thumb:** use a record whenever a class exists purely to group\nrelated data; keep domain logic in regular classes.\n",{"id":925,"difficulty":113,"q":926,"a":927},"record-components","What are record components and what does the compiler generate from them?","The identifiers in the record header are called **components**. For each\ncomponent the compiler automatically generates:\n\n- A `private final` field with the same name and type.\n- A **public accessor method** with the same name as the component (not\n  `getX()` — just `x()`).\n- A **canonical constructor** that accepts all components and assigns them.\n- `equals()`, `hashCode()`, and `toString()` based on all components.\n\n```java\nrecord Person(String name, int age) {}\n\nPerson p = new Person(\"Alice\", 30);\nSystem.out.println(p.name());     \u002F\u002F \"Alice\"  — accessor\nSystem.out.println(p.age());      \u002F\u002F 30\nSystem.out.println(p);            \u002F\u002F Person[name=Alice, age=30]\nPerson p2 = new Person(\"Alice\", 30);\nSystem.out.println(p.equals(p2)); \u002F\u002F true — all components equal\n```\n\n**Rule of thumb:** record accessors use the component name directly —\n`point.x()` not `point.getX()`.\n",{"id":929,"difficulty":113,"q":930,"a":931},"record-immutability","Are records immutable? What are the caveats?","Record fields are **`private final`**, so the reference cannot be\nreassigned after construction. However, if a component type is mutable\n(e.g., `List`, array), the object it refers to can still be mutated.\n\n```java\nrecord Scores(List\u003CInteger> values) {}\n\nScores s = new Scores(new ArrayList\u003C>(List.of(1, 2, 3)));\ns.values().add(99); \u002F\u002F legal — mutates the list inside the record\nSystem.out.println(s.values()); \u002F\u002F [1, 2, 3, 99]\n```\n\nFor true deep immutability, wrap mutable components with\n`Collections.unmodifiableList()` or copy them defensively in the\ncanonical constructor.\n\n**Rule of thumb:** records give shallow immutability; make components\ndeeply immutable yourself if needed.\n",{"id":933,"difficulty":105,"q":934,"a":935},"canonical-constructor","What is a canonical constructor and how can you customise it?","The **canonical constructor** has the same parameter list as the record\nheader. The compiler generates one automatically, but you can override it\nto add validation or normalisation:\n\n```java\nrecord Range(int min, int max) {\n    Range {                          \u002F\u002F compact canonical constructor\n        if (min > max)\n            throw new IllegalArgumentException(\"min > max\");\n        \u002F\u002F no need to write: this.min = min; this.max = max;\n        \u002F\u002F the compiler appends the assignments automatically\n    }\n}\n\nnew Range(1, 10); \u002F\u002F ok\nnew Range(10, 1); \u002F\u002F IllegalArgumentException\n```\n\nThe **compact constructor** (no parameter list, no `this.x = x` assignments)\nis the preferred style — the compiler appends the field assignments after\nyour body.\n\n**Rule of thumb:** use the compact canonical constructor for validation and\nnormalisation; let the compiler handle the field assignments.\n",{"id":937,"difficulty":105,"q":938,"a":939},"custom-constructor-in-record","Can a record have additional constructors beyond the canonical one?","Yes. A record can define **alternative constructors** that must delegate to\nthe canonical constructor as their first statement (like `this(...)`).\n\n```java\nrecord Point(double x, double y) {\n    Point() { this(0.0, 0.0); }              \u002F\u002F defaults to origin\n    Point(double x) { this(x, 0.0); }        \u002F\u002F y defaults to 0\n}\n\nPoint origin = new Point();   \u002F\u002F (0.0, 0.0)\nPoint onAxis = new Point(3.0); \u002F\u002F (3.0, 0.0)\n```\n\n**Rule of thumb:** alternative constructors must chain to the canonical\nconstructor — the canonical constructor is always the \"source of truth\" for\nfield assignment.\n",{"id":941,"difficulty":105,"q":942,"a":943},"record-vs-class","What are the restrictions that make records different from regular classes?","Records have several compiler-enforced restrictions:\n\n- **Implicitly `final`** — cannot be subclassed.\n- **Cannot extend** any class (implicitly extends `java.lang.Record`).\n- **Cannot declare instance fields** beyond the components (static fields are allowed).\n- Accessor, `equals`, `hashCode`, and `toString` can be overridden but must\n  stay consistent with component semantics.\n- **Cannot be abstract**.\n\n```java\nrecord Pair\u003CA, B>(A first, B second) {}  \u002F\u002F generic records: fine\n\u002F\u002F record MyRecord(...) extends SomeClass {} \u002F\u002F compile error\n\u002F\u002F class Child extends Pair {}              \u002F\u002F compile error — records are final\n```\n\n**Rule of thumb:** if you need inheritance or mutable state, use a regular\nclass; use a record only when the class is a pure data carrier.\n",{"id":945,"difficulty":105,"q":946,"a":947},"record-implements-interface","Can a record implement an interface?","Yes. Records can implement any number of interfaces, including providing\ncustom implementations of the interface's methods.\n\n```java\ninterface Printable { void print(); }\n\nrecord Invoice(String id, double amount) implements Printable {\n    @Override\n    public void print() {\n        System.out.printf(\"Invoice %s: $%.2f%n\", id, amount);\n    }\n}\n\nnew Invoice(\"INV-001\", 199.99).print(); \u002F\u002F Invoice INV-001: $199.99\n```\n\nRecords are commonly used with `Comparable`, `Serializable`, or custom\ndomain interfaces.\n\n**Rule of thumb:** records implement interfaces freely; they just can't\nextend a class.\n",{"id":949,"difficulty":105,"q":950,"a":951},"record-vs-lombok","How do records compare to Lombok's @Data or @Value?","| Aspect | Java Record | Lombok `@Value` \u002F `@Data` |\n|---|---|---|\n| Accessor style | `x()` | `getX()` (JavaBean convention) |\n| Immutability | Enforced by compiler | `@Value` enforces, `@Data` does not |\n| Inheritance | Cannot extend or be extended | Normal class inheritance |\n| Build tool dependency | None — JDK feature | Requires Lombok on classpath and annotation processor |\n| Customisation | Compact constructor | `@Builder`, `@NonNull`, etc. |\n\n```java\n\u002F\u002F Lombok @Value:\n@Value public class Point { int x; int y; }\npoint.getX(); \u002F\u002F JavaBean getter\n\n\u002F\u002F Java record:\nrecord Point(int x, int y) {}\npoint.x();    \u002F\u002F component accessor\n```\n\nRecords are the language-native solution; Lombok is more flexible for\nlegacy codebases that need `getX()` style or mutable builders.\n\n**Rule of thumb:** prefer records for new code on Java 16+; use Lombok when\nyou need `getX()` compatibility with frameworks like Jackson (before proper\nrecord support), or when you need mutable builders.\n",{"id":953,"difficulty":105,"q":954,"a":955},"records-with-jackson","How do you use records with Jackson for JSON serialisation?","Jackson supports records natively since **Jackson 2.12**. It serialises\nusing the component accessors and deserialises using the canonical\nconstructor. No extra annotations are needed for simple cases:\n\n```java\nrecord User(String name, int age) {}\n\nObjectMapper mapper = new ObjectMapper();\nString json = mapper.writeValueAsString(new User(\"Alice\", 30));\n\u002F\u002F {\"name\":\"Alice\",\"age\":30}\n\nUser u = mapper.readValue(json, User.class);\n\u002F\u002F User[name=Alice, age=30]\n```\n\nFor constructor parameter mapping on older Jackson versions or when\ncomponent names don't match JSON keys, add\n`@JsonProperty` on the compact constructor parameters.\n\n**Rule of thumb:** Jackson 2.12+ handles records out of the box; for\nolder versions add `jackson-module-parameter-names` and\n`-parameters` compiler flag.\n",{"id":957,"difficulty":105,"q":958,"a":959},"records-in-switch","How do records interact with pattern matching in switch expressions?","Records are first-class citizens of Java's **deconstruction patterns**\n(Java 21). You can destructure a record's components directly in a\n`switch` or `instanceof` pattern:\n\n```java\nsealed interface Shape permits Circle, Rectangle {}\nrecord Circle(double radius) implements Shape {}\nrecord Rectangle(double w, double h) implements Shape {}\n\ndouble area(Shape s) {\n    return switch (s) {\n        case Circle(double r)         -> Math.PI * r * r;\n        case Rectangle(double w, double h) -> w * h;\n    };\n}\n```\n\nThe components are bound as local variables in the case body without an\nexplicit cast or accessor call.\n\n**Rule of thumb:** records + sealed interfaces + switch pattern matching\nwork together as a modern alternative to the visitor pattern.\n",{"id":961,"difficulty":105,"q":962,"a":963},"record-serialisation","How do records behave with Java serialisation?","Records support Java serialisation natively when they implement\n`Serializable`. Serialisation is based on the **record components** rather\nthan the normal field-based mechanism, which provides better safety\nguarantees:\n\n- No `serialVersionUID` is required (though you can add one).\n- Deserialization always goes through the **canonical constructor**, so\n  validation in the compact constructor is enforced even during\n  deserialisation — unlike regular classes where deserialization bypasses\n  constructors.\n\n```java\nrecord Point(int x, int y) implements Serializable {}\n\n\u002F\u002F Serialise and deserialise:\nbyte[] bytes = serialize(new Point(1, 2));\nPoint p = (Point) deserialize(bytes); \u002F\u002F canonical constructor called\n```\n\n**Rule of thumb:** records are safer to serialise than regular classes\nbecause the canonical constructor (and its validation) is always called on\ndeserialisation.\n",{"id":965,"difficulty":105,"q":966,"a":967},"generic-records","Can records be generic?","Yes. Records support type parameters just like regular classes:\n\n```java\nrecord Pair\u003CA, B>(A first, B second) {}\nrecord Result\u003CT>(T value, String message) {}\n\nPair\u003CString, Integer> p = new Pair\u003C>(\"hello\", 42);\nSystem.out.println(p.first());   \u002F\u002F \"hello\"\nSystem.out.println(p.second());  \u002F\u002F 42\n\nResult\u003CList\u003CString>> r = new Result\u003C>(List.of(\"a\", \"b\"), \"ok\");\n```\n\nType bounds also work: `record Bounded\u003CT extends Comparable\u003CT>>(T value) {}`.\n\n**Rule of thumb:** generic records are a clean replacement for generic\ntuple or wrapper classes — concise and type-safe.\n",{"id":969,"difficulty":113,"q":970,"a":971},"record-static-members","Can records have static fields and methods?","Yes. Records can have **static fields**, **static methods**, and\n**instance methods** (beyond the generated accessors). They cannot have\nadditional non-static (instance) fields.\n\n```java\nrecord Temperature(double celsius) {\n    static final double ABSOLUTE_ZERO = -273.15;\n\n    static Temperature ofFahrenheit(double f) {\n        return new Temperature((f - 32) * 5.0 \u002F 9.0);\n    }\n\n    double toFahrenheit() {\n        return celsius * 9.0 \u002F 5.0 + 32;\n    }\n}\n\nTemperature t = Temperature.ofFahrenheit(98.6);\nSystem.out.println(t.celsius());      \u002F\u002F 37.0\nSystem.out.println(t.toFahrenheit()); \u002F\u002F 98.6\n```\n\n**Rule of thumb:** instance methods are fine in records as long as they\ndon't require mutable state — if you need mutable state, use a class.\n",{"id":973,"difficulty":113,"q":974,"a":975},"records-as-map-keys","Why are records good candidates for Map keys or Set elements?","The compiler-generated `equals()` and `hashCode()` are based on **all\ncomponents**, making records correct `Map` keys and `Set` elements\nimmediately without any manual implementation.\n\n```java\nrecord Point(int x, int y) {}\n\nMap\u003CPoint, String> labels = new HashMap\u003C>();\nlabels.put(new Point(0, 0), \"origin\");\nlabels.put(new Point(1, 0), \"unit-x\");\n\nSystem.out.println(labels.get(new Point(0, 0))); \u002F\u002F \"origin\"\n\u002F\u002F new Point(0,0).equals(new Point(0,0)) is true — hashCode matches\n```\n\nCompare with a regular class where you must manually implement\n`equals()`\u002F`hashCode()` or face silent bugs where equal-looking objects\nhash differently.\n\n**Rule of thumb:** records are safe `HashMap`\u002F`HashSet` keys out of the\nbox; regular classes need a careful `equals()`\u002F`hashCode()` override.\n",{"id":977,"difficulty":105,"q":978,"a":979},"record-local","Can records be declared locally inside a method?","Yes. **Local records** (Java 16+) can be declared inside a method, just\nlike local classes. They are useful as lightweight data holders scoped to\na single method.\n\n```java\nList\u003CString> topEmails(List\u003CUser> users) {\n    record Ranked(User user, int score) {}   \u002F\u002F local record\n\n    return users.stream()\n        .map(u -> new Ranked(u, computeScore(u)))\n        .sorted(Comparator.comparingInt(Ranked::score).reversed())\n        .limit(10)\n        .map(r -> r.user().email())\n        .toList();\n}\n```\n\nLocal records are implicitly `static` (they don't capture enclosing\ninstance state).\n\n**Rule of thumb:** local records are ideal for intermediate pipeline\nvalues that need a name but don't deserve a top-level class.\n",15,{"description":103},"Java records interview questions — record syntax, canonical constructor, compact constructor, immutability, records vs POJOs, records vs Lombok, generic records, records with interfaces, and limitations of records.","java\u002Fmodern-java\u002Frecords","LId2ywaOLWSB9Hn9ystYr978RLpW6H-v_KRdAGuKzGs",{"id":986,"title":987,"body":988,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":992,"navigation":108,"order":13,"path":993,"questions":994,"questionsCount":1063,"related":250,"seo":1064,"seoDescription":1065,"stem":1066,"subtopic":1067,"topic":28,"topicSlug":30,"updated":1068,"__hash__":1069},"qa\u002Fjava\u002Foop\u002Fclasses-objects.md","Classes Objects",{"type":100,"value":989,"toc":990},[],{"title":103,"searchDepth":29,"depth":29,"links":991},[],{},"\u002Fjava\u002Foop\u002Fclasses-objects",[995,999,1003,1007,1011,1015,1019,1023,1027,1031,1035,1039,1043,1047,1051,1055,1059],{"id":996,"difficulty":113,"q":997,"a":998},"class-vs-object","What is the difference between a class and an object?","A **class** is a *blueprint* — it defines fields (state) and methods\n(behavior). An **object** is a concrete **instance** of that blueprint,\ncreated with `new`, living on the heap with its own copy of the instance\nfields.\n\n```java\nclass Car { String color; }       \u002F\u002F blueprint\nCar a = new Car();                \u002F\u002F object 1\nCar b = new Car();                \u002F\u002F object 2 — separate state\na.color = \"red\";                  \u002F\u002F doesn't affect b\n```\n\nOne class, many objects. **Rule of thumb:** the class is the type; the\nobject is a value of that type sitting in memory.\n",{"id":1000,"difficulty":113,"q":1001,"a":1002},"encapsulation","What is encapsulation and why does it matter?","Encapsulation means keeping fields **private** and exposing controlled access\nthrough methods, so an object protects its own invariants and you can change the\ninternals without breaking callers.\n\n```java\nclass Account {\n  private double balance;           \u002F\u002F hidden state\n  public void deposit(double amt) {\n    if (amt \u003C= 0) throw new IllegalArgumentException();\n    balance += amt;                 \u002F\u002F validated mutation\n  }\n  public double getBalance() { return balance; }\n}\n```\n\nBenefits: validation in one place, freedom to refactor representation, easier\ndebugging (state changes go through known methods), and thread-safety hooks. A\npublic mutable field gives up all of these.\n",{"id":1004,"difficulty":113,"q":1005,"a":1006},"constructor","What is a constructor and what are its rules?","A constructor initializes a new object. It has the **class's name**, **no\nreturn type**, and runs when you use `new`. If you write none, the compiler\nsupplies a **default no-arg** constructor.\n\n```java\nclass User {\n  String name;\n  User() { this(\"anon\"); }      \u002F\u002F no-arg, chains\n  User(String name) { this.name = name; } \u002F\u002F parameterized\n}\n```\n\nRules interviewers probe: defining *any* constructor removes the free default\none; constructors can be overloaded; they're **not inherited** (but a subclass\nmust call one via `super`); and `private` constructors enable singletons and\nfactory-only construction.\n",{"id":1008,"difficulty":113,"q":1009,"a":1010},"constructor-vs-method","How does a constructor differ from a regular method?","- A constructor has the **same name as the class** and **no return type** (not\n  even `void`); a method has any name and a declared return type.\n- A constructor runs **once**, automatically, during `new`; a method runs when\n  you call it, as often as you like.\n- Constructors are **not inherited** and can't be `final`\u002F`static`\u002F`abstract`;\n  methods can be.\n\n```java\nclass Box {\n  int size;\n  Box(int size) { this.size = size; }   \u002F\u002F constructor\n  int size() { return size; }           \u002F\u002F method (named like a getter)\n}\n```\n\nA method *named* like the class but with a return type is just a method, not a\nconstructor — a classic trick. **Rule of thumb:** no return type + class name =\nconstructor.\n",{"id":1012,"difficulty":113,"q":1013,"a":1014},"this-keyword","What does the this keyword refer to in Java?","`this` is a reference to the **current object**. Uses: disambiguate a field\nfrom a same-named parameter, call another constructor in the same class\n(`this(...)`, constructor chaining), and pass the current instance to other\nmethods.\n\n```java\nclass Point {\n  int x, y;\n  Point(int x, int y) {\n    this.x = x;          \u002F\u002F field vs parameter\n    this.y = y;\n  }\n  Point() { this(0, 0); } \u002F\u002F chain to the other constructor\n}\n```\n\n`this(...)` for constructor chaining, like `super(...)`, must be the first\nstatement — so you can't use both in one constructor.\n",{"id":1016,"difficulty":105,"q":1017,"a":1018},"constructor-chaining","What is the order of execution when an object is constructed?","Construction runs **top-down** through the hierarchy:\n\n1. Static fields\u002Fblocks run **once** when the class first loads.\n2. On `new`: the superclass constructor runs first (via `super`), all the way\n   up to `Object`.\n3. Then instance field initializers and instance initializer blocks run.\n4. Then the rest of the subclass constructor body.\n\n```java\nclass A { A() { System.out.println(\"A ctor\"); } }\nclass B extends A {\n  int x = init();\n  int init() { System.out.println(\"B field\"); return 1; }\n  B() { System.out.println(\"B ctor\"); }\n}\n\u002F\u002F new B() prints: A ctor -> B field -> B ctor\n```\n\nA famous trap: calling an **overridable method from a constructor** runs the\nsubclass override *before* the subclass's fields are initialized — so it may see\n`null`\u002F`0`.\n",{"id":1020,"difficulty":105,"q":1021,"a":1022},"this-vs-super-ctor","Can a constructor call both this() and super()?","No. Both `this(...)` (chain to another constructor in the same class) and\n`super(...)` (chain to the parent) must be the **first statement** in a\nconstructor — and there can only be one first statement, so you use **at most\none** of them.\n\n```java\nclass Base { Base(int n) { } }\nclass Sub extends Base {\n  Sub() { this(5); }          \u002F\u002F delegates within Sub...\n  Sub(int n) { super(n); }    \u002F\u002F ...which then reaches super\n}\n```\n\nThe pattern is to funnel overloaded constructors through `this(...)` down to one\n\"primary\" constructor that finally calls `super(...)`.\n",{"id":1024,"difficulty":105,"q":1025,"a":1026},"initializer-blocks","What are instance and static initializer blocks?","- A **static initializer block** (`static { ... }`) runs **once** when the class\n  is loaded — used to set up `static` state that needs more than one line.\n- An **instance initializer block** (`{ ... }`) runs **on every `new`**, after\n  `super()` and before the constructor body — shared setup across overloaded\n  constructors.\n\n```java\nclass Config {\n  static final Map\u003CString,String> DEFAULTS;\n  static { DEFAULTS = new HashMap\u003C>(); DEFAULTS.put(\"env\", \"dev\"); }\n  final long created;\n  { created = System.currentTimeMillis(); }   \u002F\u002F runs for each instance\n}\n```\n\n**Rule of thumb:** prefer field initializers or constructors; reach for blocks\nonly when initialization needs logic (a loop, a try\u002Fcatch) that a single\nexpression can't express.\n",{"id":1028,"difficulty":105,"q":1029,"a":1030},"static-keyword","What does static mean for methods, fields and nested classes?","`static` binds a member to the **class** rather than an instance:\n\n- **static field** — one shared copy across all instances.\n- **static method** — called on the class, has **no `this`**, can't access\n  instance members directly (utility methods, factories).\n- **static nested class** — doesn't hold a reference to an outer instance.\n- **static block** — runs once at class load for static setup.\n\n```java\nclass MathUtil {\n  static final double PI = 3.14159;\n  static int square(int n) { return n * n; } \u002F\u002F MathUtil.square(5)\n}\n```\n\nBecause static methods aren't tied to an object, they **can't be overridden**\n(only *hidden*) and don't participate in runtime polymorphism.\n",{"id":1032,"difficulty":113,"q":1033,"a":1034},"instance-vs-static-members","What is the difference between instance and static members?","- An **instance member** belongs to each object — every `new` gets its own copy,\n  accessed through a reference.\n- A **static member** belongs to the class — one copy shared by all instances,\n  accessed through the class name.\n\n```java\nclass Counter {\n  static int total;     \u002F\u002F shared across all Counters\n  int id;               \u002F\u002F unique per Counter\n  Counter() { id = ++total; }\n}\nnew Counter(); new Counter();\nCounter.total;          \u002F\u002F 2 — shared\n```\n\n**Rule of thumb:** if a value or behavior is conceptually about *the type* (a\nconstant, a factory, a running count), make it `static`; if it's about *one\nobject's* state, keep it an instance member.\n",{"id":1036,"difficulty":105,"q":1037,"a":1038},"final-class-method","What does final mean for classes, methods and fields?","- **`final` class** — cannot be extended (e.g. `String`, `Integer`). Locks the\n  design and lets the JIT optimize.\n- **`final` method** — cannot be overridden by subclasses; preserves critical\n  behavior.\n- **`final` field** — assign-once; must be set by the end of construction.\n\n```java\nfinal class Constants { }          \u002F\u002F no subclassing\nclass Base {\n  final void critical() { }        \u002F\u002F subclasses can't override\n  final int id;\n  Base(int id) { this.id = id; }   \u002F\u002F final field set in ctor\n}\n```\n\nCommon reasons: immutability (a class meant to be immutable is often `final`),\nsecurity\u002Finvariant protection, and clarity of intent. Note `final` on a\nreference fixes the *reference*, not the object it points to.\n",{"id":1040,"difficulty":113,"q":1041,"a":1042},"access-modifiers","What are the four access modifiers in Java?","From most to least restrictive:\n\n- `private` — same class only.\n- *(default \u002F package-private)* — same package only (no keyword).\n- `protected` — same package **plus** subclasses (even in other packages).\n- `public` — everywhere.\n\n```java\npublic class Api {\n  private int secret;       \u002F\u002F class only\n  int packageScoped;        \u002F\u002F package\n  protected int forSubs;    \u002F\u002F package + subclasses\n  public int open;          \u002F\u002F everyone\n}\n```\n\nDefault the most restrictive that works (usually `private` fields) — it\nminimizes coupling. Note `protected` also grants package access, which surprises\npeople who think it's \"subclasses only.\"\n",{"id":1044,"difficulty":113,"q":1045,"a":1046},"getter-setter","Why use getters and setters instead of public fields?","Getters\u002Fsetters keep fields **private** while exposing access through methods,\nso you can add **validation**, change the internal representation, make a field\nread-only, or add logging\u002Flazy-loading **without changing callers**.\n\n```java\nclass Temperature {\n  private double celsius;\n  public double getFahrenheit() { return celsius * 9 \u002F 5 + 32; } \u002F\u002F derived\n  public void setCelsius(double c) {\n    if (c \u003C -273.15) throw new IllegalArgumentException();        \u002F\u002F validated\n    this.celsius = c;\n  }\n}\n```\n\nA `public` field locks the API to a raw value forever. **Rule of thumb:** expose\nbehavior, not data — but don't add a getter\u002Fsetter for *every* field reflexively;\nonly where encapsulation buys something (records are better for pure data).\n",{"id":1048,"difficulty":126,"q":1049,"a":1050},"nested-classes","What are the types of nested classes in Java?","- **Static nested class** — declared `static`; no link to an outer instance, a\n  namespaced helper.\n- **Inner (non-static) class** — holds an implicit reference to its enclosing\n  instance; can access its outer fields.\n- **Local class** — declared inside a method.\n- **Anonymous class** — an unnamed inner class created and instantiated at once.\n\n```java\nclass Outer {\n  static class Helper { }            \u002F\u002F static nested\n  class Inner { }                    \u002F\u002F inner — needs an Outer instance\n  Runnable r = new Runnable() {      \u002F\u002F anonymous\n    public void run() { }\n  };\n}\n```\n\nGotcha: a non-static inner class keeps the outer object alive (potential memory\nleak), so prefer `static` nested classes unless you actually need the enclosing\ninstance.\n",{"id":1052,"difficulty":105,"q":1053,"a":1054},"object-creation","What are the ways to create an object in Java?","- **`new`** — the normal path, invokes a constructor.\n- **Factory method** — e.g. `List.of()`, `Integer.valueOf()`, your own\n  `Builder.build()`.\n- **`Class.getDeclaredConstructor().newInstance()`** — reflection.\n- **`clone()`** — copy an existing object.\n- **Deserialization** — reconstruct from bytes (bypasses constructors).\n\n```java\nUser a = new User();                          \u002F\u002F new\nList\u003CInteger> b = List.of(1, 2);              \u002F\u002F factory\nUser c = User.class.getDeclaredConstructor().newInstance(); \u002F\u002F reflection\n```\n\nNote that reflection and deserialization can create objects **without running a\nconstructor**, which is why immutability\u002Fsingletons sometimes need extra guards.\n",{"id":1056,"difficulty":105,"q":1057,"a":1058},"private-constructor","When would you make a constructor private?","A `private` constructor blocks outside `new`, which enables several patterns:\n\n- **Singleton** — one shared instance handed out by a static accessor.\n- **Static factory only** — force creation through named methods (`of`,\n  `valueOf`) that can cache or pick a subtype.\n- **Utility class** — a class of only `static` members that should never be\n  instantiated.\n\n```java\nfinal class MathUtil {\n  private MathUtil() { }                 \u002F\u002F no instances\n  static int square(int n) { return n * n; }\n}\nenum Config { INSTANCE; }                \u002F\u002F the preferred singleton\n```\n\n**Rule of thumb:** if a class shouldn't be instantiated freely (utility,\nsingleton, factory-controlled), hide the constructor — but for singletons an\n`enum` is the safest implementation.\n",{"id":1060,"difficulty":126,"q":1061,"a":1062},"immutable-class","How do you design an immutable class?","Make the state impossible to change after construction:\n\n1. Mark the class `final` (no subclass can add mutability).\n2. Make all fields `private final`.\n3. Set everything in the constructor; provide **no setters**.\n4. **Defensively copy** mutable fields in and out (don't leak internal refs).\n\n```java\nfinal class Range {\n  private final int[] bounds;\n  Range(int[] bounds) { this.bounds = bounds.clone(); } \u002F\u002F copy in\n  int[] bounds() { return bounds.clone(); }             \u002F\u002F copy out\n}\n```\n\nImmutables are inherently **thread-safe**, cacheable, and safe as map keys —\n`String`, `Integer`, and `LocalDate` are all built this way. (A `record` gives\nyou most of this for free.)\n",17,{"description":103},"Java classes and objects interview questions — constructors and chaining, this vs super, static vs instance members, final, access modifiers, initializer blocks, nested classes, immutability and the ways to create an object.","java\u002Foop\u002Fclasses-objects","Classes & Objects","2026-06-19","2pfVZGzp6e4jnHO-oLqGtkNngzqwiKj2njOAk0RZJaY",{"id":1071,"title":1072,"body":1073,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":1077,"navigation":108,"order":13,"path":1078,"questions":1079,"questionsCount":904,"related":250,"seo":1164,"seoDescription":1165,"stem":1166,"subtopic":1167,"topic":55,"topicSlug":56,"updated":809,"__hash__":1168},"qa\u002Fjava\u002Fstreams-functional\u002Flambdas-functional-interfaces.md","Lambdas Functional Interfaces",{"type":100,"value":1074,"toc":1075},[],{"title":103,"searchDepth":29,"depth":29,"links":1076},[],{},"\u002Fjava\u002Fstreams-functional\u002Flambdas-functional-interfaces",[1080,1084,1088,1092,1096,1100,1104,1108,1112,1116,1120,1124,1128,1132,1136,1140,1144,1148,1152,1156,1160],{"id":1081,"difficulty":113,"q":1082,"a":1083},"what-is-a-lambda","What is a lambda expression in Java?","A lambda is an **anonymous function** — a block of behavior you can pass around\nas a value, without writing a named method or a class. It's compact syntax for\nimplementing a **functional interface** (an interface with a single abstract\nmethod). Introduced in **Java 8**, it brought functional-style programming to\nthe language.\n\n```java\n\u002F\u002F verbose anonymous class\nRunnable r1 = new Runnable() {\n  public void run() { System.out.println(\"hi\"); }\n};\n\n\u002F\u002F same thing as a lambda\nRunnable r2 = () -> System.out.println(\"hi\");\n```\n\nThe compiler matches the lambda to the interface's single method, so `r2`'s body\n*becomes* `run()`. Lambdas make code that takes behavior as a parameter\n(callbacks, comparators, stream operations) far less verbose.\n",{"id":1085,"difficulty":113,"q":1086,"a":1087},"lambda-syntax-variants","What are the different lambda syntax forms?","A lambda is `parameters -> body`. The parts can be written several ways\ndepending on how many parameters there are and whether the body is one\nexpression or a block.\n\n```java\n()        -> 42                 \u002F\u002F no params, expression body\nx         -> x * 2             \u002F\u002F one param, parens optional\n(x)       -> x * 2            \u002F\u002F one param, explicit parens\n(x, y)    -> x + y           \u002F\u002F multiple params need parens\n(int x, int y) -> x + y      \u002F\u002F explicit types (rare; usually inferred)\n(x, y)    -> { return x + y; } \u002F\u002F block body needs { } and return\n```\n\nKey rules: **single-expression** bodies have no braces and no `return` (the value\nis implicit); a **block** body needs braces *and* an explicit `return` if it\nreturns a value. Parameter types are usually inferred, so you omit them.\n",{"id":1089,"difficulty":113,"q":1090,"a":1091},"functional-interface","What is a functional interface?","A functional interface is an interface with exactly **one abstract method**\n(a **SAM** — Single Abstract Method). That single method is the target a lambda\nor method reference implements. It can still have any number of `default` and\n`static` methods — those don't count toward the one-abstract-method rule.\n\n```java\n@FunctionalInterface\ninterface Transformer {\n  String apply(String s);          \u002F\u002F the one abstract method\n  default String twice(String s) { return apply(apply(s)); } \u002F\u002F allowed\n}\n\nTransformer upper = s -> s.toUpperCase();\n```\n\nExamples in the JDK: `Runnable`, `Callable`, `Comparator`, and everything in\n`java.util.function`. Because there's only one abstract method, the compiler\nknows unambiguously which method your lambda body implements.\n",{"id":1093,"difficulty":105,"q":1094,"a":1095},"functional-interface-annotation","What does the @FunctionalInterface annotation do?","`@FunctionalInterface` is an **optional** marker that tells the compiler \"this\ninterface is meant to have exactly one abstract method.\" If you accidentally add\na second abstract method, the build **fails** — it's a safety net, not a\nrequirement.\n\n```java\n@FunctionalInterface\ninterface Calc {\n  int op(int a, int b);\n  \u002F\u002F int other(int x);  \u002F\u002F would cause a COMPILE ERROR\n}\n```\n\nThe annotation has no runtime effect; a lambda works on any interface with one\nabstract method whether or not it's annotated. But adding it documents intent and\n**protects callers** who rely on lambda compatibility from a careless edit.\nNote methods inherited from `Object` (like `equals`) don't count as abstract.\n",{"id":1097,"difficulty":105,"q":1098,"a":1099},"function-package-table","What are the core interfaces in java.util.function?","`java.util.function` provides the **general-purpose** functional interfaces so\nyou rarely need to write your own. The four families are Function, Consumer,\nSupplier, and Predicate, plus operator\u002Ftwo-arg variants:\n\n| Interface | Abstract method | Takes \u002F returns |\n| --------- | --------------- | --------------- |\n| `Function\u003CT,R>` | `R apply(T t)` | T -> R |\n| `BiFunction\u003CT,U,R>` | `R apply(T,U)` | (T,U) -> R |\n| `Supplier\u003CT>` | `T get()` | () -> T |\n| `Consumer\u003CT>` | `void accept(T t)` | T -> void |\n| `BiConsumer\u003CT,U>` | `void accept(T,U)` | (T,U) -> void |\n| `Predicate\u003CT>` | `boolean test(T t)` | T -> boolean |\n| `BiPredicate\u003CT,U>` | `boolean test(T,U)` | (T,U) -> boolean |\n| `UnaryOperator\u003CT>` | `T apply(T t)` | T -> T |\n| `BinaryOperator\u003CT>` | `T apply(T,T)` | (T,T) -> T |\n\n`UnaryOperator` and `BinaryOperator` are just `Function`\u002F`BiFunction` specialized\nto a single type — handy for things like `String::trim` or `Integer::sum`.\n",{"id":1101,"difficulty":113,"q":1102,"a":1103},"function-interface","What is the Function interface used for?","`Function\u003CT,R>` represents a **transformation**: it takes one argument of type\n`T` and returns a result of type `R` via `apply`. It's the workhorse behind\n`Stream.map`.\n\n```java\nFunction\u003CString, Integer> length = s -> s.length();\nlength.apply(\"hello\");          \u002F\u002F 5\n\n\u002F\u002F used in a stream\nList\u003CInteger> lens = names.stream()\n                          .map(String::length)\n                          .toList();\n```\n\nWhen input and output are the *same* type, prefer `UnaryOperator\u003CT>` for\nclarity. For two inputs use `BiFunction\u003CT,U,R>`.\n",{"id":1105,"difficulty":113,"q":1106,"a":1107},"supplier-consumer","What is the difference between Supplier and Consumer?","They're mirror images. A **`Supplier\u003CT>`** takes **no input** and **produces** a\nvalue (`T get()`) — a factory or lazy source. A **`Consumer\u003CT>`** **takes** a\nvalue and **returns nothing** (`void accept(T)`) — a side effect like printing\nor storing.\n\n```java\nSupplier\u003CDouble> rng = () -> Math.random();  \u002F\u002F produces\nrng.get();\n\nConsumer\u003CString> printer = s -> System.out.println(s); \u002F\u002F consumes\nprinter.accept(\"hi\");\n```\n\nSuppliers power lazy evaluation (`Optional.orElseGet`, `Logger` message\nsuppliers); consumers power `forEach` and `Optional.ifPresent`. Think of it as\n**output-only vs input-only**.\n",{"id":1109,"difficulty":113,"q":1110,"a":1111},"predicate-interface","What is the Predicate interface?","`Predicate\u003CT>` takes a `T` and returns a **boolean** via `test` — it represents a\ncondition. It's what `Stream.filter` expects.\n\n```java\nPredicate\u003CInteger> isEven = n -> n % 2 == 0;\nisEven.test(4);                 \u002F\u002F true\n\nList\u003CInteger> evens = nums.stream()\n                          .filter(isEven)\n                          .toList();\n```\n\nPredicates compose with `and`, `or`, and `negate` (covered separately), letting\nyou build complex conditions from simple ones. For two arguments use\n`BiPredicate\u003CT,U>`.\n",{"id":1113,"difficulty":105,"q":1114,"a":1115},"andthen-compose","What is the difference between andThen and compose on Function?","Both **chain** two functions, but in opposite order. `f.andThen(g)` runs **f\nfirst, then g** on f's result. `f.compose(g)` runs **g first, then f** — matching\nthe mathematical `f(g(x))`.\n\n```java\nFunction\u003CInteger,Integer> times2 = x -> x * 2;\nFunction\u003CInteger,Integer> plus3  = x -> x + 3;\n\ntimes2.andThen(plus3).apply(5);  \u002F\u002F (5*2)+3 = 13\ntimes2.compose(plus3).apply(5);  \u002F\u002F (5+3)*2 = 16\n```\n\nMnemonic: **andThen reads left-to-right** (do this, *and then* that);\n**compose reads inside-out**. Both return a *new* `Function`, leaving the\noriginals untouched.\n",{"id":1117,"difficulty":105,"q":1118,"a":1119},"predicate-composition","How do you combine predicates with and, or, and negate?","`Predicate` has three default composition methods that return a **new** predicate:\n**`and`** (both must pass), **`or`** (either passes), and **`negate`** (flips the\nresult). They let you build readable compound conditions.\n\n```java\nPredicate\u003CString> notBlank = s -> !s.isBlank();\nPredicate\u003CString> shortStr = s -> s.length() \u003C 10;\n\nPredicate\u003CString> valid = notBlank.and(shortStr);\nPredicate\u003CString> blank = notBlank.negate();\nPredicate\u003CString> either = notBlank.or(shortStr);\n\nvalid.test(\"hello\");            \u002F\u002F true\n```\n\n`and` short-circuits like `&&` (skips the second test if the first fails). There's\nalso a static `Predicate.not(...)` (Java 11+) so you can negate a method\nreference: `filter(Predicate.not(String::isBlank))`.\n",{"id":1121,"difficulty":105,"q":1122,"a":1123},"method-references","What is a method reference and what are its four kinds?","A method reference (`::`) is shorthand for a lambda that **just calls an existing\nmethod**. When a lambda does nothing but forward its arguments to one method, a\nmethod reference is cleaner. There are **four kinds**:\n\n| Kind | Syntax | Lambda equivalent |\n| ---- | ------ | ----------------- |\n| Static | `Integer::parseInt` | `s -> Integer.parseInt(s)` |\n| Bound instance | `out::println` (specific object) | `s -> out.println(s)` |\n| Unbound instance | `String::toUpperCase` (type) | `s -> s.toUpperCase()` |\n| Constructor | `ArrayList::new` | `() -> new ArrayList\u003C>()` |\n\n```java\nFunction\u003CString,Integer> parse = Integer::parseInt;     \u002F\u002F static\nConsumer\u003CString> print = System.out::println;           \u002F\u002F bound\nFunction\u003CString,String> up = String::toUpperCase;       \u002F\u002F unbound\nSupplier\u003CList\u003CString>> make = ArrayList::new;           \u002F\u002F constructor\n```\n\nThe compiler infers which method from the target functional interface's signature.\n",{"id":1125,"difficulty":126,"q":1126,"a":1127},"bound-vs-unbound","What is the difference between a bound and unbound instance method reference?","Both reference an instance method, but differ in **who supplies the receiver**\n(the object the method runs on). A **bound** reference captures a *specific*\nobject now; an **unbound** reference uses the *first argument* as the receiver.\n\n```java\nString prefix = \"Hello, \";\n\u002F\u002F BOUND — receiver is the captured `prefix` object\nFunction\u003CString,String> greet = prefix::concat;\ngreet.apply(\"Ada\");             \u002F\u002F \"Hello, Ada\"\n\n\u002F\u002F UNBOUND — receiver is the lambda's first arg\nFunction\u003CString,Integer> len = String::length;\nlen.apply(\"Ada\");               \u002F\u002F 3  (called as \"Ada\".length())\n```\n\nTell them apart by the left side of `::`: a **value\u002Fvariable** is bound, a\n**type name** is unbound. For an unbound reference the functional interface has\none *extra* leading parameter for the receiver.\n",{"id":1129,"difficulty":126,"q":1130,"a":1131},"effectively-final","What does \"effectively final\" mean for variables captured by a lambda?","A lambda may **capture** local variables from its enclosing scope, but only ones\nthat are **final or effectively final** — meaning assigned exactly once and never\nreassigned afterward (even without the `final` keyword). Reassigning a captured\nvariable is a **compile error**.\n\n```java\nint factor = 3;                 \u002F\u002F effectively final — never reassigned\nFunction\u003CInteger,Integer> f = x -> x * factor;  \u002F\u002F OK\n\nint counter = 0;\nRunnable bad = () -> counter++; \u002F\u002F COMPILE ERROR — counter is reassigned\n```\n\nInstance and static fields are *not* subject to this — only **local variables**.\nThe restriction exists because the lambda captures a **copy of the value**, so\nallowing reassignment would create confusing divergence between the two copies.\n",{"id":1133,"difficulty":126,"q":1134,"a":1135},"mutable-capture-workaround","Why can't a lambda mutate a captured local variable, and what's the workaround?","Because the lambda may **outlive** the method that created it (it can be stored\nand run later, possibly on another thread). Java captures locals **by value**, so\nletting you mutate the original would be ambiguous and unsafe. The fix is to\nmutate **state held inside an object** the variable points to, rather than the\nvariable itself.\n\n```java\n\u002F\u002F won't compile: total is a reassigned local\n\u002F\u002F int total = 0; list.forEach(n -> total += n);\n\nint[] total = {0};              \u002F\u002F array holds mutable state\nlist.forEach(n -> total[0] += n);\n\nAtomicInteger sum = new AtomicInteger();   \u002F\u002F thread-safe alternative\nlist.forEach(sum::addAndGet);\n```\n\nThat said, the *idiomatic* answer is to avoid mutation entirely — use a stream\nreduction (`mapToInt(...).sum()`) instead of accumulating into a captured variable.\n",{"id":1137,"difficulty":126,"q":1138,"a":1139},"lambda-vs-anonymous-class","What is the difference between a lambda and an anonymous inner class?","They look similar but differ in important ways:\n\n| Aspect | Lambda | Anonymous class |\n| ------ | ------ | --------------- |\n| `this` | refers to the **enclosing** instance | refers to the **anonymous object** |\n| New scope | **no** new scope (shares the method's) | introduces its own scope |\n| Shadowing | can't shadow enclosing locals | can declare same-named locals |\n| Compilation | **`invokedynamic`** (no extra `.class`) | generates a separate `.class` file |\n| State | only the SAM (one method) | can have fields and multiple methods |\n\n```java\nRunnable lambda = () -> System.out.println(this); \u002F\u002F enclosing `this`\nRunnable anon = new Runnable() {\n  public void run() { System.out.println(this); } \u002F\u002F the Runnable itself\n};\n```\n\nThe `this` binding is the classic interview gotcha: inside a lambda, `this` is the\nsurrounding object, *not* the functional-interface instance.\n",{"id":1141,"difficulty":126,"q":1142,"a":1143},"invokedynamic","How are lambdas compiled — do they create a class file?","No. Unlike anonymous classes (which generate a `Foo$1.class` at compile time),\nlambdas are compiled to an **`invokedynamic`** bytecode instruction plus a private\nsynthetic method holding the body. At **runtime** the JVM's `LambdaMetafactory`\nbuilds the implementation **lazily** on first use.\n\n```text\nanonymous class -> extra .class file generated at compile time\nlambda          -> invokedynamic; implementation linked at runtime\n```\n\nBenefits: **no class-file explosion**, smaller jars, and the JVM can optimize the\nstrategy over time. A stateless lambda that captures nothing may even be reused as\na **singleton**. This is why lambdas are generally lighter than anonymous classes.\n",{"id":1145,"difficulty":105,"q":1146,"a":1147},"target-typing","What is target typing for a lambda?","A lambda has **no inherent type** — its type is determined by the **context** it\nappears in, called the **target type**. The same lambda can implement different\nfunctional interfaces depending on the variable, parameter, or return type it's\nassigned to.\n\n```java\nRunnable r       = () -> doWork();          \u002F\u002F target type Runnable\nCallable\u003CVoid> c = () -> { doWork(); return null; };\n\nComparator\u003CString> byLen = (a, b) -> a.length() - b.length();\n\u002F\u002F the SAME shape could fit any (String,String)->int interface\n```\n\nThe compiler reads the target type, finds its single abstract method, and checks\nthe lambda's parameters and return against that signature. This is why a lambda\ncan't be assigned to `var` (no target to infer from) or `Object`.\n",{"id":1149,"difficulty":126,"q":1150,"a":1151},"exceptions-in-lambdas","How do you handle checked exceptions in a lambda?","A lambda may only throw checked exceptions that its **target functional\ninterface declares**. The `java.util.function` interfaces declare **none**, so a\nlambda calling a checked-exception method won't compile — you must handle it.\n\n```java\n\u002F\u002F won't compile: Files.readString throws IOException\n\u002F\u002F Function\u003CPath,String> f = p -> Files.readString(p);\n\nFunction\u003CPath,String> f = p -> {\n  try { return Files.readString(p); }\n  catch (IOException e) { throw new UncheckedIOException(e); }\n};\n```\n\nOptions: **try\u002Fcatch inside** the lambda (often wrapping in an unchecked\nexception), use an interface that *does* declare the exception (e.g. `Callable`),\nor write a small \"throwing function\" wrapper utility. There's no\nbuilt-in checked-exception-friendly functional interface.\n",{"id":1153,"difficulty":105,"q":1154,"a":1155},"primitive-specializations","Why does java.util.function have primitive specializations like IntFunction?","To **avoid autoboxing**. Using `Function\u003CInteger,Integer>` boxes every `int` into\nan `Integer` object on the heap — costly in hot loops and streams. The primitive\nspecializations work directly on `int`, `long`, and `double`, eliminating that\noverhead.\n\n| Specialization | Signature |\n| -------------- | --------- |\n| `IntFunction\u003CR>` | `int -> R` |\n| `ToIntFunction\u003CT>` | `T -> int` |\n| `IntUnaryOperator` | `int -> int` |\n| `IntBinaryOperator` | `(int,int) -> int` |\n| `IntPredicate` | `int -> boolean` |\n| `IntSupplier` \u002F `IntConsumer` | `() -> int` \u002F `int -> void` |\n\n```java\nIntUnaryOperator square = x -> x * x;   \u002F\u002F no boxing\nsquare.applyAsInt(5);                    \u002F\u002F 25\n```\n\n`IntStream`, `LongStream`, and `DoubleStream` use these throughout, which is why\n`mapToInt(...).sum()` is faster than mapping to boxed `Integer`s.\n",{"id":1157,"difficulty":105,"q":1158,"a":1159},"comparator-lambdas","How are lambdas and method references used to build Comparators?","`Comparator` is a functional interface, so you can write one as a lambda — but the\n**factory methods** `comparing`, `thenComparing`, and `reversed` make it far\ncleaner, and they take method references for the sort key.\n\n```java\n\u002F\u002F raw lambda\nComparator\u003CPerson> byAge = (a, b) -> Integer.compare(a.age(), b.age());\n\n\u002F\u002F idiomatic: key extractor + chaining\nComparator\u003CPerson> c = Comparator\n    .comparing(Person::lastName)\n    .thenComparing(Person::firstName)\n    .reversed();\n\npeople.sort(c);\n```\n\n`comparing` takes a `Function` (the key extractor) and builds the comparison for\nyou. For primitive keys use `comparingInt`\u002F`comparingDouble` to avoid boxing.\nThis is one of the most common real-world uses of method references.\n",{"id":1161,"difficulty":105,"q":1162,"a":1163},"lambda-scope-this","What does `this` refer to inside a lambda?","Inside a lambda, **`this` refers to the enclosing instance** — the object whose\nmethod contains the lambda — *not* to the functional-interface object the lambda\nbecomes. This is because a lambda does **not** create a new scope; it's\nlexically part of its surrounding method.\n\n```java\nclass Widget {\n  String name = \"panel\";\n  Runnable make() {\n    return () -> System.out.println(this.name); \u002F\u002F \"panel\" — Widget's this\n  }\n}\n```\n\nContrast with an anonymous class, where `this` is the anonymous object itself, so\naccessing the outer instance needs `Widget.this`. This lexical-`this` behavior\nmakes lambdas more intuitive for capturing enclosing state, and is a frequent\ninterview discriminator between the two.\n",{"description":103},"Java lambdas interview questions — lambda syntax, functional interfaces, the java.util.function package, method references, effectively final capture, and @FunctionalInterface.","java\u002Fstreams-functional\u002Flambdas-functional-interfaces","Lambdas & Functional Interfaces","D3Nqup9i8dd4bJPaz03ykKMLDyiKfRtLrhT87UWh9iQ",{"id":1170,"title":1171,"body":1172,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":1176,"navigation":108,"order":29,"path":1177,"questions":1178,"questionsCount":805,"related":250,"seo":1265,"seoDescription":1266,"stem":1267,"subtopic":1268,"topic":46,"topicSlug":48,"updated":809,"__hash__":1269},"qa\u002Fjava\u002Fcollections\u002Fhashmap-internals.md","Hashmap Internals",{"type":100,"value":1173,"toc":1174},[],{"title":103,"searchDepth":29,"depth":29,"links":1175},[],{},"\u002Fjava\u002Fcollections\u002Fhashmap-internals",[1179,1183,1187,1191,1195,1199,1203,1207,1211,1214,1218,1222,1226,1230,1234,1238,1242,1246,1249,1253,1257,1261],{"id":1180,"difficulty":105,"q":1181,"a":1182},"how-hashmap-works","How does a HashMap work internally?","A `HashMap` stores entries in an **array of buckets** (`Node\u003CK,V>[] table`).\nEach bucket holds a chain of `Node` objects, where a `Node` packs the key's\n**hash**, the **key**, the **value**, and a **`next`** pointer to the following\nnode in the same bucket.\n\n```java\nstatic class Node\u003CK,V> {\n  final int hash;   \u002F\u002F cached spread hash of the key\n  final K key;\n  V value;\n  Node\u003CK,V> next;   \u002F\u002F chains entries in the same bucket\n}\n```\n\nOn `put`, the key's hash picks a bucket index; the entry is stored there (or\nappended to the chain on a collision). On `get`, the same index is computed and\nthe chain is scanned with `equals` to find the matching key. With a good hash,\noperations are average **O(1)**; the array is resized as it fills to keep chains\nshort.\n",{"id":1184,"difficulty":126,"q":1185,"a":1186},"hashing-spread-function","What is the spread (perturbation) function and why does HashMap apply it?","The bucket index is computed as `(n - 1) & hash`, which only keeps the **low\nbits** of the hash (since `n` is a power of two). If two keys differ only in\ntheir high bits, they'd collide. To mix high bits down into the low ones,\n`HashMap` applies a **spread** function before indexing.\n\n```java\nstatic final int hash(Object key) {\n  int h;\n  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);\n}\n```\n\nXORing the hash with its own upper 16 bits is cheap (one shift, one XOR) yet\nmeaningfully reduces collisions for hashes whose entropy lives in the high bits.\nNote a **null key** is mapped to hash `0`, which is why it always lands in\nbucket 0.\n",{"id":1188,"difficulty":105,"q":1189,"a":1190},"index-calculation","How does HashMap convert a hash into a bucket index?","It uses **`index = (n - 1) & hash`**, where `n` is the table length. Because `n`\nis always a power of two, `n - 1` is a mask of all-ones in the low bits, so the\nbitwise `&` is equivalent to `hash % n` but far faster than a modulo.\n\n```java\nint n = 16;              \u002F\u002F table length, a power of two\nint idx = (n - 1) & hash; \u002F\u002F 15 & hash  ->  keeps the low 4 bits\n```\n\nThis is the whole reason capacity must be a power of two: the `&` trick only\ndistributes entries evenly across all buckets when `n - 1` is a clean low-bit\nmask. A non-power-of-two `n` would leave some buckets unreachable.\n",{"id":1192,"difficulty":126,"q":1193,"a":1194},"why-power-of-two","Why must HashMap capacity always be a power of two?","Two reasons, both about the `(n - 1) & hash` indexing. First, **speed**: a\nbitwise AND replaces an expensive modulo. Second, **distribution**: when `n` is\na power of two, `n - 1` is `0b...0111…1`, so the AND keeps a contiguous block of\nlow bits and every bucket is reachable. If `n` weren't a power of two, the mask\nwould have gaps and some buckets could never be hit.\n\n```java\n\u002F\u002F HashMap rounds any requested capacity up to the next power of two\nnew HashMap\u003C>(10);  \u002F\u002F actual table capacity becomes 16\nnew HashMap\u003C>(20);  \u002F\u002F becomes 32\n```\n\nThe constructor runs `tableSizeFor` to round your requested initial capacity up\nto the nearest power of two, so you can never actually create a non-power-of-two\ntable.\n",{"id":1196,"difficulty":126,"q":1197,"a":1198},"put-flow","Walk through what happens on a put() call.","1. Compute the **spread hash** of the key.\n2. Compute the bucket index `(n - 1) & hash`.\n3. If the bucket is **empty**, drop the new node in.\n4. If occupied, **scan the chain**: a node matching by `hash` *and*\n   `equals` means an existing key — overwrite its value and return the old one.\n5. Otherwise **append** a new node; if the chain length crosses **8** (and the\n   table is ≥ 64), **treeify** the bucket.\n6. Increment `size`; if `size > threshold` (capacity × load factor), **resize**.\n\n```java\nmap.put(\"a\", 1);  \u002F\u002F new bucket\nmap.put(\"a\", 2);  \u002F\u002F same key -> value replaced, returns 1\nmap.put(\"b\", 3);  \u002F\u002F collision? append to chain\n```\n\nThe match step is why `equals` is essential: same bucket does **not** mean same\nkey — the chain must be walked and compared.\n",{"id":1200,"difficulty":105,"q":1201,"a":1202},"get-flow","Walk through what happens on a get() call.","`get` mirrors `put`'s lookup half: spread the key's hash, compute the index, then\n**scan the bucket**. For each node it first compares the cached **hash** (a cheap\nint compare) and only then calls **`equals`** — the hash check short-circuits\nmost mismatches.\n\n```java\nV get(Object key) {\n  \u002F\u002F hash -> index -> walk chain\n  \u002F\u002F return node where node.hash == h && (k == node.key || k.equals(node.key))\n}\n```\n\nIn a linked-list bucket this is **O(chain length)**; in a treeified bucket it's\n**O(log n)**. A missing key returns `null` — which is indistinguishable from a\nkey mapped *to* `null`, so use `containsKey` when that difference matters.\n",{"id":1204,"difficulty":105,"q":1205,"a":1206},"collision-handling","How does HashMap handle hash collisions?","When two keys map to the same bucket (a **collision**), `HashMap` chains them.\nOriginally every bucket is a **singly linked list** of `Node`s. As of Java 8,\nonce a single bucket's chain grows past a threshold the bucket is converted to a\n**red-black tree** so lookups within it stay logarithmic rather than linear.\n\n```text\nbucket[5] -> Node(k1) -> Node(k2) -> Node(k3)   \u002F\u002F linked list\n\n\u002F\u002F after treeification:\nbucket[5] -> (balanced red-black tree of TreeNodes)\n```\n\nSo a collision degrades the *bucket* from O(1) toward O(log n) at worst (with a\nreasonable `hashCode`), not toward O(n). Distinct keys can collide even with\nperfect hashCodes simply because many hashes fold into the same small index.\n",{"id":1208,"difficulty":126,"q":1209,"a":1210},"treeification","What is treeification and when does it happen?","**Treeification** converts a bucket from a linked list to a **red-black tree**\nwhen it gets too long, bounding worst-case lookups at **O(log n)** instead of\nO(n). Two conditions must both hold:\n\n| Constant | Value | Meaning |\n| -------- | ----- | ------- |\n| `TREEIFY_THRESHOLD` | 8 | chain length that triggers treeify |\n| `MIN_TREEIFY_CAPACITY` | 64 | table must be at least this big |\n| `UNTREEIFY_THRESHOLD` | 6 | tree shrinks back to a list at\u002Fbelow this |\n\n```java\n\u002F\u002F if a bucket reaches 8 nodes but table \u003C 64,\n\u002F\u002F HashMap resizes instead of treeifying\n```\n\nIf the table is smaller than 64, a long chain usually means the table is just too\nsmall, so `HashMap` **resizes** rather than treeifying. The gap between 8 and 6\n(hysteresis) avoids flip-flopping between tree and list on repeated add\u002Fremove.\n",{"id":130,"difficulty":105,"q":1212,"a":1213},"What are the default initial capacity and load factor, and what do they mean?","The defaults are **initial capacity 16** and **load factor 0.75**. The load\nfactor is the fullness fraction at which the table grows: the **threshold** =\ncapacity × load factor, so a default map resizes when it holds more than\n`16 × 0.75 = 12` entries.\n\n```java\nnew HashMap\u003C>();            \u002F\u002F capacity 16, threshold 12\nnew HashMap\u003C>(32, 0.5f);    \u002F\u002F capacity 32, threshold 16\n```\n\n`0.75` is a deliberate **time\u002Fspace trade-off**: lower factors waste memory but\nreduce collisions; higher factors save memory but lengthen chains. If you know\nthe final size, presize with `new HashMap\u003C>(expected \u002F 0.75 + 1)` to avoid\nrepeated resizes.\n",{"id":1215,"difficulty":126,"q":1216,"a":1217},"resizing-rehash","What happens during a HashMap resize?","When `size` exceeds the threshold, `HashMap` **doubles the capacity** (a new\npower-of-two table) and **rehashes** every entry into the larger table. Doubling\nkeeps the power-of-two invariant so `(n - 1) & hash` stays valid.\n\n```java\n\u002F\u002F Java 8 split trick: with capacity doubled, an entry either stays\n\u002F\u002F at index i, or moves to index i + oldCapacity — decided by one bit:\nif ((node.hash & oldCapacity) == 0)  \u002F\u002F stays in \"low\" bucket\nelse                                  \u002F\u002F moves to \"high\" bucket\n```\n\nBecause only the **single new high bit** of the hash decides where an entry\ngoes, Java 8 splits each old bucket's chain into exactly two ordered sub-chains\nwithout recomputing indexes from scratch. Resizing is **O(n)** and rebuilds the\ntable, which is why presizing matters for large maps.\n",{"id":1219,"difficulty":126,"q":1220,"a":1221},"hashcode-equals-contract","What is the hashCode\u002Fequals contract and why must HashMap keys honor it?","The contract: if `a.equals(b)` then `a.hashCode() == b.hashCode()`\n**must** hold (the reverse need not — unequal objects may share a hash). `equals`\nmust also be reflexive, symmetric, transitive, and consistent.\n\n```java\nclass Point {\n  int x, y;\n  @Override public boolean equals(Object o) { \u002F* compare x,y *\u002F }\n  @Override public int hashCode() { return Objects.hash(x, y); }\n}\n```\n\n`HashMap` relies on this directly: it uses `hashCode` to find the **bucket** and\n`equals` to find the **key** within it. Override only one and a key you stored\nbecomes unfindable — `get` lands in the wrong bucket (or the right bucket but\nfails the `equals` check) and returns `null`. Always override the **two\ntogether**.\n",{"id":1223,"difficulty":126,"q":1224,"a":1225},"bad-hashcode-on","How can a bad hashCode degrade HashMap to O(n)?","If `hashCode` returns the **same value for every key** (e.g. `return 42;` or\n`return 0;`), every entry hashes to one bucket. That single bucket becomes one\ngiant chain, so `get`\u002F`put` must scan it linearly — **O(n)** per operation,\ndefeating the whole point of a hash map.\n\n```java\nclass Bad {\n  @Override public int hashCode() { return 1; } \u002F\u002F all collide!\n}\n\u002F\u002F 10,000 Bad keys -> one bucket of 10,000 nodes -> O(n) lookups\n```\n\nTreeification softens but doesn't fix this: the bucket becomes a red-black tree,\nimproving to **O(log n)** — and only if the keys are also `Comparable`, otherwise\nit falls back to a list. A well-distributed `hashCode` is the real cure.\n",{"id":1227,"difficulty":105,"q":1228,"a":1229},"null-keys-values","Can a HashMap store null keys and null values?","Yes — `HashMap` allows **one null key** and **any number of null values**. The\nnull key is special-cased to hash `0`, so it always sits in **bucket 0**.\n\n```java\nMap\u003CString, String> m = new HashMap\u003C>();\nm.put(null, \"x\");   \u002F\u002F legal — single null key\nm.put(\"a\", null);   \u002F\u002F legal — null value\nm.get(\"missing\");   \u002F\u002F null — but is the key absent or mapped to null?\nSystem.out.println(m.containsKey(\"a\")); \u002F\u002F true, even though value is null\n```\n\nThe ambiguity of a `null` return is the catch: `get` returns `null` both for an\nabsent key and a key mapped to `null`. Use **`containsKey`** to tell them apart.\nContrast with `Hashtable` and `ConcurrentHashMap`, which forbid nulls entirely.\n",{"id":1231,"difficulty":126,"q":1232,"a":1233},"fail-fast-iterators","What are fail-fast iterators and ConcurrentModificationException?","`HashMap`'s iterators are **fail-fast**: they track a `modCount` and throw\n**`ConcurrentModificationException`** if the map is structurally modified (add or\nremove) during iteration through any path other than the iterator itself.\n\n```java\nfor (String k : map.keySet()) {\n  if (k.startsWith(\"x\")) map.remove(k);  \u002F\u002F throws CME\n}\n\n\u002F\u002F safe: remove through the iterator\nIterator\u003CString> it = map.keySet().iterator();\nwhile (it.hasNext()) { if (it.next().startsWith(\"x\")) it.remove(); }\n```\n\nFail-fast is a **best-effort bug detector**, not a guarantee — it's specified as\n\"throws on a best-effort basis,\" so never write logic that depends on the\nexception. To mutate while iterating, use `iterator.remove()`, collect-then-\nremove, or `removeIf`.\n",{"id":1235,"difficulty":126,"q":1236,"a":1237},"hashmap-not-thread-safe","Why is HashMap not thread-safe, and what was the infinite-loop bug?","`HashMap` has **no synchronization**, so concurrent `put`s can interleave and\ncorrupt the table — lost updates, wrong `size`, or a thread seeing a half-built\nstate. The most infamous case was an **infinite loop on resize** in pre-Java-8\nJDKs.\n\n```text\nold resize() reversed each bucket's chain while transferring it;\ntwo threads resizing at once could splice A -> B -> A into a cycle,\nso a later get() would spin forever at 100% CPU.\n```\n\nJava 8 changed resize to preserve chain order (the low\u002Fhigh split), which removed\n*that* specific cycle — but `HashMap` is **still not thread-safe** and can lose\ndata or throw under concurrency. For shared maps use **`ConcurrentHashMap`**;\n`Collections.synchronizedMap` works but locks the whole map.\n",{"id":1239,"difficulty":105,"q":1240,"a":1241},"immutable-keys","Why should HashMap keys be immutable?","A key's hash is **computed when it's inserted** and used to pick its bucket. If\nyou then mutate a field that affects `hashCode`\u002F`equals`, the key's new hash\npoints to a **different bucket** than where it's actually stored — so the map can\nno longer find it.\n\n```java\nSet\u003CList\u003CInteger>> s = new HashSet\u003C>();\nList\u003CInteger> key = new ArrayList\u003C>(List.of(1, 2));\ns.add(key);\nkey.add(3);                     \u002F\u002F mutates the key's hashCode!\nSystem.out.println(s.contains(key)); \u002F\u002F false — lost in the wrong bucket\n```\n\nThe entry becomes a \"ghost\": present in the map but unreachable by `get` or\n`contains`, and possibly duplicated on re-insert. Prefer **immutable keys**\n(`String`, `Integer`, records, frozen value objects) so the hash can never drift.\n",{"id":1243,"difficulty":105,"q":1244,"a":1245},"hashmap-vs-linkedhashmap-vs-treemap","What is the difference between HashMap, LinkedHashMap and TreeMap?","All implement `Map`, but they differ in **ordering** and **complexity**:\n\n| Map | Ordering | get\u002Fput | Backing structure |\n| --- | -------- | ------- | ----------------- |\n| `HashMap` | **none** (arbitrary) | O(1) avg | hash table |\n| `LinkedHashMap` | **insertion** (or access) order | O(1) avg | hash table + linked list |\n| `TreeMap` | **sorted** by key | O(log n) | red-black tree |\n\n```java\nnew HashMap\u003C>();        \u002F\u002F fastest, no order guarantee\nnew LinkedHashMap\u003C>();  \u002F\u002F predictable iteration order\nnew TreeMap\u003C>();        \u002F\u002F keys come out sorted; needs Comparable\u002FComparator\n```\n\nPick `HashMap` by default, `LinkedHashMap` when you need stable iteration order\nor an **LRU cache** (access-order mode + `removeEldestEntry`), and `TreeMap` when\nyou need sorted keys or range queries (`firstKey`, `headMap`, `subMap`).\n",{"id":1247,"difficulty":126,"q":135,"a":1248},"hashmap-vs-hashtable-vs-chm","| Feature | `HashMap` | `Hashtable` | `ConcurrentHashMap` |\n| ------- | --------- | ----------- | ------------------- |\n| Thread-safe | no | yes (whole-method `synchronized`) | yes (fine-grained) |\n| Null key\u002Fvalues | 1 null key, null values | none | none |\n| Locking | — | one lock for the whole table | per-bucket \u002F CAS |\n| Status | preferred single-thread | **legacy** | preferred concurrent |\n\n```java\nMap\u003CString,Integer> m = new ConcurrentHashMap\u003C>();\nm.compute(\"k\", (k, v) -> v == null ? 1 : v + 1); \u002F\u002F atomic, no external lock\n```\n\n`Hashtable` is a legacy class that locks every method, so it serializes all\naccess — slow and effectively retired. **`ConcurrentHashMap`** locks at the\nbucket\u002Fbin level (with CAS for hot paths), so many threads can write to\ndifferent buckets in parallel. Its iterators are **weakly consistent** (no\n`ConcurrentModificationException`).\n",{"id":1250,"difficulty":126,"q":1251,"a":1252},"chm-internals","How does ConcurrentHashMap achieve thread safety without a global lock?","Modern `ConcurrentHashMap` (Java 8+) abandoned the old segment design for the\nsame `Node[]` table as `HashMap`, plus **per-bin locking** and **CAS**. An empty\nbin is filled with a lock-free **compare-and-swap**; a non-empty bin is updated\nunder a `synchronized` block on the bin's **first node** — so contention is\nlimited to the keys colliding in that one bin.\n\n```java\nConcurrentHashMap\u003CString,Long> counts = new ConcurrentHashMap\u003C>();\ncounts.merge(\"hit\", 1L, Long::sum);   \u002F\u002F atomic increment, thread-safe\n```\n\nReads are **non-blocking** (fields are `volatile`), so `get` never locks. Resizes\nare **cooperative**: multiple threads help transfer bins concurrently. This is\nwhy it scales far better than `Hashtable`'s single lock while still being fully\ncorrect.\n",{"id":1254,"difficulty":126,"q":1255,"a":1256},"treenode-comparable","What happens when treeified keys are not Comparable?","A treeified bucket is a **red-black tree**, which normally orders nodes by the\nkey's `compareTo`. If the keys don't implement **`Comparable`**, `HashMap` can't\nsort them, so it falls back to **comparing identity hash codes** and uses a\ntie-breaking routine (`tieBreakOrder`) to keep the tree balanced — searches then\neffectively scan rather than binary-search within ties.\n\n```java\n\u002F\u002F keys with equal hash but no Comparable order:\n\u002F\u002F tree falls back to System.identityHashCode() ordering for placement\n```\n\nThe practical takeaway: treeification still **bounds** worst case better than a\nplain list, but you only get the full **O(log n)** lookup benefit when colliding\nkeys are mutually `Comparable`. A good `hashCode` (so buckets never treeify) is\nstill the best defense.\n",{"id":1258,"difficulty":113,"q":1259,"a":1260},"hashset-backing","How is HashSet implemented on top of HashMap?","`HashSet` is a thin wrapper around a `HashMap`: it stores each element as a\n**key**, mapping every key to a single shared dummy value (a constant `PRESENT`\nobject). So all of `HashSet`'s behavior — hashing, buckets, load factor,\ntreeification — is just `HashMap`'s.\n\n```java\nprivate static final Object PRESENT = new Object();\npublic boolean add(E e) {\n  return map.put(e, PRESENT) == null;  \u002F\u002F null means key was new\n}\n```\n\nThis is why `HashSet` has the same **O(1)** average operations, the same\n**null-element-allowed** rule, and the same requirement that elements have a\nproper `hashCode`\u002F`equals`. `LinkedHashSet` and `TreeSet` likewise wrap\n`LinkedHashMap` and `TreeMap`.\n",{"id":1262,"difficulty":105,"q":1263,"a":1264},"presize-hashmap","How should you size a HashMap to avoid resizing?","Each resize is an **O(n) rehash**, so for a map you'll fill to a known size,\npresize it. Because resize triggers at `capacity × 0.75`, request an initial\ncapacity of about **expected \u002F 0.75 + 1** so the table never crosses its\nthreshold during loading.\n\n```java\nint expected = 1000;\nMap\u003CString,Integer> m = new HashMap\u003C>((int)(expected \u002F 0.75f) + 1);\n\n\u002F\u002F Java 19+: clearer intent, does the math for you\nMap\u003CString,Integer> m2 = HashMap.newHashMap(expected);\n```\n\nPassing the raw expected size (`new HashMap\u003C>(1000)`) is a common mistake — it\nrounds to capacity 1024 but still resizes at 768 entries. Java 19's\n`HashMap.newHashMap(n)` factory expresses \"I will hold n entries\" directly.\n",{"description":103},"Java HashMap internals interview questions — buckets and hashing, load factor and resizing, treeification, collision handling, hashCode\u002Fequals contract, and HashMap vs ConcurrentHashMap vs Hashtable.","java\u002Fcollections\u002Fhashmap-internals","HashMap Internals","aUEBoW19JTqJbSySvGUbVVFn43b_ZfXDBSwzWvGsAvw",{"id":1271,"title":1272,"body":1273,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":1277,"navigation":108,"order":29,"path":1278,"questions":1279,"questionsCount":1370,"related":250,"seo":1371,"seoDescription":1372,"stem":1373,"subtopic":1374,"topic":72,"topicSlug":74,"updated":809,"__hash__":1375},"qa\u002Fjava\u002Fconcurrency\u002Fsynchronization-locks.md","Synchronization Locks",{"type":100,"value":1274,"toc":1275},[],{"title":103,"searchDepth":29,"depth":29,"links":1276},[],{},"\u002Fjava\u002Fconcurrency\u002Fsynchronization-locks",[1280,1284,1288,1292,1296,1300,1304,1308,1310,1314,1318,1322,1326,1330,1334,1338,1342,1346,1350,1353,1357,1359,1363,1366],{"id":1281,"difficulty":105,"q":1282,"a":1283},"what-is-synchronization","What is synchronization and what problem does it solve?","**Synchronization** restricts a block of code so that only **one thread at a\ntime** can execute it (mutual exclusion) and ensures changes made by one thread\nare **visible** to others. It exists to fix the **race condition**: when two\nthreads access shared mutable state concurrently and at least one writes, the\nfinal result depends on unpredictable timing.\n\n```java\nint count = 0;\nvoid inc() { count++; }   \u002F\u002F NOT atomic: read, add, write\n```\n\n`count++` is three steps; two threads can both read the same value and one\nupdate is lost. The vulnerable region — the code touching shared state — is the\n**critical section**, and synchronization serializes access to it.\n",{"id":1285,"difficulty":113,"q":1286,"a":1287},"critical-section","What is a critical section?","A **critical section** is a region of code that accesses **shared mutable\nstate** and must not be executed by more than one thread simultaneously.\nProtecting it with a lock guarantees that interleaved access can't corrupt the\ndata.\n\n```java\nsynchronized (lock) {\n  \u002F\u002F critical section: only one thread in here at a time\n  balance += amount;\n}\n```\n\nThe goal is to make the critical section **as small as correctness allows** —\nhold the lock just long enough to read\u002Fmodify the shared data, no longer, so\nother threads aren't blocked unnecessarily.\n",{"id":1289,"difficulty":105,"q":1290,"a":1291},"synchronized-keyword","How does the synchronized keyword work?","`synchronized` acquires an object's **intrinsic lock** (also called its\n**monitor**) before entering, and releases it on exit — even if an exception is\nthrown. While one thread holds the lock, any other thread trying to synchronize\non the **same object** blocks.\n\n```java\nsynchronized void m() { ... }          \u002F\u002F locks on 'this'\nsynchronized (lockObj) { ... }         \u002F\u002F locks on lockObj\nstatic synchronized void s() { ... }   \u002F\u002F locks on the Class object\n```\n\nIt can be applied to a **method** (locks the receiver, or the `Class` for static\nmethods) or a **block** (you choose the lock object). Two threads synchronizing\non *different* objects don't block each other at all.\n",{"id":1293,"difficulty":105,"q":1294,"a":1295},"synchronized-method-vs-block","What is the difference between a synchronized method and a synchronized block?","A **synchronized method** implicitly locks the **whole method body** on `this`\n(or the `Class` for static methods). A **synchronized block** lets you lock only\na **portion** of the method, and on **any object you choose**.\n\n```java\nsynchronized void update() {        \u002F\u002F entire method under lock\n  prepare();                        \u002F\u002F doesn't need the lock — wasteful\n  shared.modify();\n}\n\nvoid update2() {\n  prepare();                        \u002F\u002F runs concurrently\n  synchronized (lock) {             \u002F\u002F only the critical part is locked\n    shared.modify();\n  }\n}\n```\n\nBlocks give **finer granularity** (shorter lock hold time, higher concurrency)\nand let you avoid locking on `this`, which is the safer practice.\n",{"id":1297,"difficulty":105,"q":1298,"a":1299},"intrinsic-lock-object","What object does a synchronized method lock on?","It depends on whether the method is static:\n\n| Method kind | Lock acquired |\n| ----------- | ------------- |\n| instance `synchronized` method | the **instance** (`this`) |\n| static `synchronized` method | the **`Class` object** (e.g. `Foo.class`) |\n| `synchronized (obj)` block | whatever `obj` you name |\n\n```java\nclass Foo {\n  synchronized void a() {}        \u002F\u002F locks 'this'\n  static synchronized void b() {} \u002F\u002F locks Foo.class\n}\n```\n\nCrucially, the instance lock and the `Class` lock are **different monitors** —\nso `a()` and `b()` can run **concurrently** on the same object. Mixing static\nand instance synchronization without realizing this is a common bug.\n",{"id":1301,"difficulty":105,"q":1302,"a":1303},"reentrancy","What does it mean that intrinsic locks are reentrant?","**Reentrant** means a thread that already holds a lock can acquire it **again**\nwithout deadlocking itself. The JVM tracks an owner and a hold count;\nre-entering increments it, exiting decrements it, and the lock frees only when\nthe count hits zero.\n\n```java\nsynchronized void outer() {\n  inner();          \u002F\u002F re-acquires the same lock — fine\n}\nsynchronized void inner() { ... }\n```\n\nWithout reentrancy, `outer()` calling `inner()` (both locking `this`) would\nblock forever. This is why a synchronized method can freely call other\nsynchronized methods on the same object. `ReentrantLock` provides the same\nbehavior explicitly.\n",{"id":1305,"difficulty":126,"q":1306,"a":1307},"happens-before","What memory visibility guarantee does a lock provide?","A lock establishes a **happens-before** relationship: everything a thread does\n**before releasing** a lock is **visible** to any thread that **subsequently\nacquires** the same lock. So locks aren't just about mutual exclusion — they\nalso flush writes to main memory and invalidate stale cached reads.\n\n```java\nsynchronized (lock) { data = 42; }   \u002F\u002F write happens-before release\n\u002F\u002F another thread:\nsynchronized (lock) { read(data); }  \u002F\u002F sees 42 — acquire sees prior release\n```\n\nWithout synchronization (or `volatile`), one thread's write to a field may\n**never** become visible to another due to CPU caching and reordering. This\nvisibility guarantee is why you can't fix a race with `synchronized` on writes\nbut unsynchronized reads — both sides must use the lock.\n",{"id":304,"difficulty":126,"q":305,"a":1309},"They coordinate threads on an object's **monitor**. `wait()` **releases the\nlock** and parks the thread until another thread calls `notify()`\u002F`notifyAll()`\non the **same object**; the woken thread must **re-acquire** the lock before\ncontinuing. `notify()` wakes **one** waiting thread, `notifyAll()` wakes **all**.\n\n```java\nsynchronized (queue) {\n  while (queue.isEmpty())   \u002F\u002F guard in a loop, not an if\n    queue.wait();           \u002F\u002F releases lock, sleeps until notified\n  process(queue.remove());\n}\n\u002F\u002F producer:\nsynchronized (queue) { queue.add(x); queue.notifyAll(); }\n```\n\nYou **must hold the monitor** to call any of them, or you get\n`IllegalMonitorStateException`. Prefer `notifyAll()` unless you can prove a\nsingle waiter is always the right one.\n",{"id":1311,"difficulty":126,"q":1312,"a":1313},"wait-while-loop","Why must wait() be called inside a while loop?","Because a thread can return from `wait()` for reasons other than the condition\nbecoming true: **spurious wakeups** (the JVM is allowed to wake a thread for no\nreason) and the fact that with `notifyAll()` **multiple** threads wake and race,\nso by the time one re-acquires the lock the condition may be false again.\n\n```java\n\u002F\u002F WRONG — assumes the condition holds after waking\nif (queue.isEmpty()) queue.wait();\n\n\u002F\u002F RIGHT — re-checks after every wakeup\nwhile (queue.isEmpty()) queue.wait();\n```\n\nThe `while` loop **re-tests the predicate** after re-acquiring the lock, so the\nthread only proceeds when the condition is genuinely satisfied. Using `if`\ninstead of `while` here is one of the most common concurrency bugs.\n",{"id":1315,"difficulty":105,"q":1316,"a":1317},"illegal-monitor-state","When do you get IllegalMonitorStateException?","When you call `wait()`, `notify()`, or `notifyAll()` on an object **without\nholding that object's monitor** — i.e. outside a `synchronized` block\u002Fmethod\nlocked on the *same* object.\n\n```java\nObject lock = new Object();\nlock.wait();   \u002F\u002F IllegalMonitorStateException — no lock held\n\nsynchronized (lock) {\n  lock.wait(); \u002F\u002F fine — we own the monitor\n}\n```\n\nThe rule exists because these methods atomically manipulate the wait set and the\nlock, which only makes sense if the caller already owns the monitor. A frequent\nmistake is calling `notify()` on a different object than the one threads are\nwaiting on — same exception.\n",{"id":1319,"difficulty":105,"q":1320,"a":1321},"lock-interface","What is the Lock interface and why use it over synchronized?","`java.util.concurrent.locks.Lock` is an **explicit** lock object whose API\noffers capabilities intrinsic locks lack: **`tryLock()`** (non-blocking or\ntimed), **`lockInterruptibly()`** (abandon a lock attempt on interrupt),\n**fairness** policies, and **multiple `Condition`s** per lock.\n\n```java\nLock lock = new ReentrantLock();\nlock.lock();\ntry {\n  \u002F\u002F critical section\n} finally {\n  lock.unlock();   \u002F\u002F MUST unlock in finally\n}\n```\n\nThe trade-off: it's **manual** — you must `unlock()` in a `finally`, or a thrown\nexception leaks the lock forever. Use `synchronized` for simple cases (it can't\nleak); reach for `Lock` when you need try\u002Ftimeout\u002Finterruptible acquisition or\nseparate wait conditions.\n",{"id":1323,"difficulty":105,"q":1324,"a":1325},"reentrantlock-finally","Why must you unlock a ReentrantLock in a finally block?","Unlike `synchronized`, an explicit `Lock` is **not** released automatically when\na block exits or an exception propagates. If you `lock()` and then the body\nthrows, the lock stays held — every other thread blocks forever (a deadlock you\ncaused by leaking the lock).\n\n```java\nlock.lock();\ntry {\n  risky();          \u002F\u002F may throw\n} finally {\n  lock.unlock();    \u002F\u002F always runs, even on exception\n}\n```\n\nAlso acquire the lock **outside** the `try` (or as its first statement) so you\nnever call `unlock()` for a lock you didn't get. This boilerplate is the price\nof the extra flexibility `Lock` gives you.\n",{"id":1327,"difficulty":105,"q":1328,"a":1329},"trylock","What does tryLock() do?","`tryLock()` attempts to acquire the lock **without blocking**: it returns `true`\nif it got the lock, `false` immediately if another thread holds it. The timed\noverload `tryLock(time, unit)` waits up to a bound, then gives up.\n\n```java\nif (lock.tryLock()) {\n  try { doWork(); } finally { lock.unlock(); }\n} else {\n  \u002F\u002F lock busy — do something else instead of blocking\n}\n\nif (lock.tryLock(2, TimeUnit.SECONDS)) { ... }  \u002F\u002F bounded wait\n```\n\nThis enables **deadlock avoidance** (back off if you can't get all needed locks)\nand **responsiveness** (don't hang indefinitely). Only call `unlock()` when\n`tryLock()` actually returned `true`.\n",{"id":1331,"difficulty":126,"q":1332,"a":1333},"lock-interruptibly","What is lockInterruptibly() and why does it matter?","`lockInterruptibly()` acquires the lock but **responds to interruption** while\nwaiting: if another thread interrupts the blocked thread, it throws\n`InterruptedException` instead of waiting indefinitely. Plain `synchronized` and\n`lock()` are **not** interruptible — a thread stuck waiting on them can't be\ncancelled.\n\n```java\ntry {\n  lock.lockInterruptibly();\n  try { doWork(); } finally { lock.unlock(); }\n} catch (InterruptedException e) {\n  Thread.currentThread().interrupt();  \u002F\u002F restore the flag, bail out\n}\n```\n\nThis matters for **cancellable** tasks and graceful shutdown: a worker waiting\nfor a contended lock can be told to stop rather than hanging the whole system.\n",{"id":1335,"difficulty":126,"q":1336,"a":1337},"lock-fairness","What is lock fairness and what is its trade-off?","A **fair** lock grants access in **FIFO order** — the longest-waiting thread\nacquires it next. The default `ReentrantLock` (and `synchronized`) is\n**unfair**: it may let a newly-arriving thread \"barge\" ahead of queued waiters.\n\n```java\nLock fair   = new ReentrantLock(true);  \u002F\u002F FIFO, no starvation\nLock unfair = new ReentrantLock();      \u002F\u002F default, higher throughput\n```\n\nFairness **prevents starvation** but costs **throughput**, because barging lets\nthe lock stay hot on a CPU that already has it cached and avoids context\nswitches. Use a fair lock only when you have measured starvation; otherwise the\nfaster unfair default is preferred.\n",{"id":1339,"difficulty":126,"q":1340,"a":1341},"readwritelock","What is a ReadWriteLock and when is it useful?","A `ReadWriteLock` (impl: `ReentrantReadWriteLock`) splits one lock into a\n**read lock** and a **write lock**. Multiple threads may hold the **read lock\nsimultaneously** (reads don't conflict), but the **write lock is exclusive** —\nno other readers or writers while a writer holds it.\n\n```java\nReadWriteLock rw = new ReentrantReadWriteLock();\nrw.readLock().lock();\ntry { return cache.get(key); } finally { rw.readLock().unlock(); }\n\nrw.writeLock().lock();\ntry { cache.put(k, v); } finally { rw.writeLock().unlock(); }\n```\n\nIt shines for **read-heavy, write-rare** data (caches, config) because readers\nno longer serialize against each other. Under heavy writes it offers little over\na plain lock, and writers can starve unless you choose a fair policy.\n",{"id":1343,"difficulty":126,"q":1344,"a":1345},"stampedlock","What is StampedLock and how does it differ from ReadWriteLock?","`StampedLock` (Java 8) is a more performant alternative offering three modes:\nwriting, reading, and a unique **optimistic read**. Each acquisition returns a\n**stamp** you pass to the release method. The optimistic read takes **no lock**\n— you read, then `validate()` the stamp to check no writer intervened.\n\n```java\nlong stamp = sl.tryOptimisticRead();   \u002F\u002F no locking\nint x = field;\nif (!sl.validate(stamp)) {              \u002F\u002F a writer slipped in?\n  stamp = sl.readLock();                \u002F\u002F fall back to a real read lock\n  try { x = field; } finally { sl.unlockRead(stamp); }\n}\n```\n\nIt's faster under read-heavy load but **not reentrant** and trickier to use\ncorrectly. Use it as a tuned replacement for `ReadWriteLock` only when profiling\njustifies the complexity.\n",{"id":1347,"difficulty":126,"q":1348,"a":1349},"condition-vs-wait-notify","How do Condition objects compare to wait\u002Fnotify?","A `Condition` is the `Lock` equivalent of wait\u002Fnotify: `await()` parks and\nreleases the lock, `signal()`\u002F`signalAll()` wake waiters. The key advantage is\nthat **one `Lock` can have multiple `Condition`s**, so you can wait on and\nsignal **distinct predicates** separately instead of one shared wait set.\n\n```java\nLock lock = new ReentrantLock();\nCondition notFull  = lock.newCondition();\nCondition notEmpty = lock.newCondition();\n\u002F\u002F producer waits on notFull \u002F signals notEmpty; consumer the reverse\n```\n\nAs with wait, you must **hold the lock** and loop on the predicate. Separate\nconditions let a bounded buffer signal only the threads that can actually\nproceed, avoiding the \"wake everyone\" waste of a single monitor.\n",{"id":296,"difficulty":126,"q":1351,"a":1352},"What is a deadlock and what four conditions cause it?","A **deadlock** is two or more threads each waiting for a lock the other holds, so\nnone can ever proceed. It requires **all four** Coffman conditions\nsimultaneously:\n\n| Condition | Meaning |\n| --------- | ------- |\n| Mutual exclusion | a resource is held exclusively |\n| Hold and wait | a thread holds one lock while requesting another |\n| No preemption | locks can't be forcibly taken away |\n| Circular wait | a cycle of threads each waiting on the next |\n\n```java\n\u002F\u002F Thread 1: synchronized(A){ synchronized(B){} }\n\u002F\u002F Thread 2: synchronized(B){ synchronized(A){} }   \u002F\u002F opposite order -> deadlock\n```\n\nBreak **any one** condition to prevent it — the practical lever is eliminating\ncircular wait via consistent lock ordering.\n",{"id":1354,"difficulty":126,"q":1355,"a":1356},"prevent-deadlock-ordering","How do you prevent deadlock with lock ordering?","Impose a **global, consistent order** in which all threads acquire locks. If\nevery thread always grabs locks in the same sequence, a **cycle is impossible**,\nso circular wait — and thus deadlock — can't occur.\n\n```java\n\u002F\u002F order by a stable key (e.g. account id) so both threads agree\nAccount first  = a.id \u003C b.id ? a : b;\nAccount second = a.id \u003C b.id ? b : a;\nsynchronized (first) {\n  synchronized (second) { transfer(a, b); }\n}\n```\n\nOther tactics: use `tryLock` with a timeout and back off on failure, shrink lock\nscope so you hold only one lock at a time, or replace fine-grained locks with a\nsingle coarse lock. Lock ordering is the most common and reliable answer.\n",{"id":300,"difficulty":105,"q":301,"a":1358},"**Starvation** is when a thread is perpetually denied a resource it needs —\ne.g. low-priority threads never scheduled, or threads losing every race for an\nunfair lock. **Livelock** is when threads are **active but make no progress**:\nthey keep responding to each other and repeatedly retrying without ever\nadvancing.\n\n```java\n\u002F\u002F livelock: both keep yielding to each other, neither proceeds\nwhile (!tryLock(a) || !tryLock(b)) { unlockAll(); \u002F* retry immediately *\u002F }\n```\n\nUnlike deadlock, livelocked threads aren't blocked — they burn CPU. Fixes\ninclude **randomized back-off** before retrying, **fair locks** to cure\nstarvation, and ensuring some thread eventually wins.\n",{"id":1360,"difficulty":126,"q":1361,"a":1362},"what-to-lock-on","What object should you synchronize on?","Prefer a **private final lock object** dedicated to guarding the state. Avoid\nlocking on `this` (callers can lock your object and interfere), on a\n**`String` literal** or `Boolean`\u002Fboxed `Integer` (interned\u002Fcached — *other*\nunrelated code may lock the same instance), or on a mutable reference (the lock\nidentity changes).\n\n```java\nprivate final Object lock = new Object();   \u002F\u002F good: encapsulated\nvoid update() { synchronized (lock) { ... } }\n```\n\nA private lock means **only your class** controls the monitor, so no external\ncode can cause deadlock or contention on it. Locking on `this` or a public field\nleaks your synchronization policy to the world.\n",{"id":218,"difficulty":105,"q":1364,"a":1365},"What are synchronized collections and their limits?","`Collections.synchronizedList\u002FMap\u002FSet(...)` wrap a collection so each\n**individual method** is synchronized on the wrapper. That makes single calls\nthread-safe, but **compound operations** (check-then-act, iteration) are **not**\natomic and still need external locking.\n\n```java\nList\u003CString> list = Collections.synchronizedList(new ArrayList\u003C>());\nlist.add(\"x\");                       \u002F\u002F atomic\n\nsynchronized (list) {                \u002F\u002F must lock manually to iterate\n  for (String s : list) { ... }      \u002F\u002F else ConcurrentModificationException\n}\n```\n\nThey also serialize *every* access on one lock, hurting throughput. For\nconcurrent use, prefer `java.util.concurrent` collections like\n`ConcurrentHashMap` or `CopyOnWriteArrayList`, which use finer-grained or\nlock-free strategies.\n",{"id":1367,"difficulty":126,"q":1368,"a":1369},"lock-granularity","What is lock granularity (coarse vs fine-grained locking)?","**Granularity** is how much data a single lock protects. **Coarse-grained** —\none lock for everything — is **simple and safe** but kills concurrency, since\nunrelated operations serialize. **Fine-grained** — many small locks — allows\nmore parallelism but risks **deadlock** and adds overhead.\n\n```java\n\u002F\u002F coarse: one lock, no concurrency between buckets\nsynchronized (map) { ... }\n\n\u002F\u002F fine: lock per bucket\u002Fsegment -> independent buckets run in parallel\nsynchronized (bucketLocks[hash & MASK]) { ... }\n```\n\n`ConcurrentHashMap` is the classic example of fine-grained locking done right\n(lock striping \u002F per-bin locks). The engineering trade-off: start coarse for\ncorrectness, then split locks only where contention is **measured**, since\nfiner locks compound deadlock and complexity risk.\n",24,{"description":103},"Java synchronization interview questions — the synchronized keyword and intrinsic locks, the Lock interface and ReentrantLock, ReadWriteLock, deadlock, and wait\u002Fnotify coordination.","java\u002Fconcurrency\u002Fsynchronization-locks","Synchronization & Locks","yJCsVbBnEcJtUY69FArcqKG14k_TAZcr9aWKCrJWoA0",{"id":1377,"title":1378,"body":1379,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":1383,"navigation":108,"order":29,"path":1384,"questions":1385,"questionsCount":904,"related":250,"seo":1468,"seoDescription":1469,"stem":1470,"subtopic":448,"topic":63,"topicSlug":65,"updated":809,"__hash__":1471},"qa\u002Fjava\u002Fexceptions\u002Ftry-with-resources.md","Try With Resources",{"type":100,"value":1380,"toc":1381},[],{"title":103,"searchDepth":29,"depth":29,"links":1382},[],{},"\u002Fjava\u002Fexceptions\u002Ftry-with-resources",[1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1424,1428,1432,1436,1440,1444,1448,1452,1456,1460,1464],{"id":1387,"difficulty":113,"q":1388,"a":1389},"what-is-try-with-resources","What is try-with-resources and what problem does it solve?","Try-with-resources (Java 7+) is a `try` statement that **declares one or more\nresources** in parentheses and **closes them automatically** when the block\nfinishes — normally or via an exception. It replaces the error-prone\nmanual-`finally` cleanup pattern, eliminating **resource leaks**.\n\n```java\n\u002F\u002F Automatic: br is closed no matter how the block exits\ntry (BufferedReader br = new BufferedReader(new FileReader(\"a.txt\"))) {\n    return br.readLine();\n}\n```\n\nA resource is anything that must be released — files, sockets, DB connections,\nstreams. Any object that implements **`AutoCloseable`** can be a resource. The\nproblem it solves: developers routinely forgot the `finally` close, nested it\nwrong, or let a `close()` exception swallow the real one.\n",{"id":1391,"difficulty":105,"q":1392,"a":1393},"manual-finally-boilerplate","What did the equivalent cleanup code look like before try-with-resources?","You had to declare the resource **outside** the `try`, close it in a `finally`,\nand null-check because the constructor might have failed. It was verbose and\neasy to get wrong.\n\n```java\nBufferedReader br = null;\ntry {\n    br = new BufferedReader(new FileReader(\"a.txt\"));\n    return br.readLine();\n} finally {\n    if (br != null) br.close();   \u002F\u002F close itself can throw IOException\n}\n```\n\nWith two resources you'd nest two `try\u002Ffinally` blocks (closing the outer one\neven if the inner constructor threw). Try-with-resources collapses all of that\ninto one parenthesized declaration — **less code, no leaks, and correct\nexception handling**.\n",{"id":1395,"difficulty":105,"q":1396,"a":1397},"autocloseable-interface","What is the AutoCloseable interface?","`AutoCloseable` (Java 7, in `java.lang`) is the **single-method interface** that\nmakes a class usable as a try-with-resources resource. Its only method is\n`close()`, declared to throw the broadest checked exception, `Exception`.\n\n```java\npublic interface AutoCloseable {\n    void close() throws Exception;\n}\n```\n\nOnly types implementing `AutoCloseable` (or its subtype `Closeable`) may appear\nin the resource list — anything else is a compile error. The compiler guarantees\n`close()` is invoked when the block exits, so implementing this interface is all\nit takes to plug a custom type into automatic resource management.\n",{"id":1399,"difficulty":105,"q":1400,"a":1401},"closeable-vs-autocloseable","What is the difference between Closeable and AutoCloseable?","`Closeable` (Java 5, in `java.io`) predates try-with-resources and was\n**retrofitted to extend `AutoCloseable`** in Java 7, so every `Closeable` works\nas a resource. The differences are in the `close()` contract:\n\n| | `AutoCloseable` | `Closeable` |\n| --- | --- | --- |\n| Package | `java.lang` | `java.io` |\n| `close()` throws | `Exception` (broad) | `IOException` (narrow) |\n| Idempotent? | not required | **required** — repeat calls have no effect |\n| Use for | any resource | I\u002FO streams |\n\n```java\npublic interface Closeable extends AutoCloseable {\n    void close() throws IOException;\n}\n```\n\nPrefer implementing `Closeable` when your resource is I\u002FO-related, and\n`AutoCloseable` for everything else (e.g. a lock or a transaction).\n",{"id":1403,"difficulty":105,"q":1404,"a":1405},"close-method-signature","Why does AutoCloseable.close() declare a broader exception than Closeable.close()?","`AutoCloseable` is the **general** abstraction, so its `close()` throws\n`Exception` to allow any resource — a DB connection, a JNI handle — to report\nwhatever failure it has. `Closeable` is **I\u002FO-specific**, so it narrows to\n`IOException`, which is more precise for stream code.\n\n```java\n\u002F\u002F AutoCloseable: may throw any checked exception\nvoid close() throws Exception;\n\u002F\u002F Closeable: I\u002FO resources, narrower contract\nvoid close() throws IOException;\n```\n\nAn implementation can always **narrow** the declared exception (override\n`throws Exception` with `throws IOException`, or `throws` nothing at all).\nThrowing nothing is encouraged: a `close()` that can't fail is far easier to use\nsafely.\n",{"id":1407,"difficulty":105,"q":1408,"a":1409},"idempotent-close","What does it mean that Closeable.close() must be idempotent?","**Idempotent** means calling `close()` a second (or third) time has **no\nadditional effect** and doesn't throw. `Closeable` mandates this; `AutoCloseable`\nonly *recommends* it.\n\n```java\nReader r = new FileReader(\"a.txt\");\nr.close();\nr.close();   \u002F\u002F safe — Closeable.close() is idempotent, does nothing\n```\n\nIt matters because a resource can be closed both **explicitly** in your code and\n**automatically** by try-with-resources, and you don't want the second close to\nblow up. When you write your own `close()`, guarding it with a `boolean closed`\nflag makes it idempotent.\n",{"id":1411,"difficulty":126,"q":1412,"a":1413},"compiler-desugaring","How does the compiler translate try-with-resources?","The compiler **desugars** it into an ordinary `try\u002Ffinally` with the close call\nand **suppressed-exception bookkeeping** baked in. Roughly:\n\n```java\n\u002F\u002F try (Resource r = ...) { body }\n\u002F\u002F becomes:\nResource r = ...;\nThrowable primary = null;\ntry {\n    body;\n} catch (Throwable t) {\n    primary = t;\n    throw t;\n} finally {\n    if (r != null) {\n        if (primary != null) {\n            try { r.close(); }\n            catch (Throwable sup) { primary.addSuppressed(sup); }\n        } else {\n            r.close();   \u002F\u002F body succeeded; let close throw normally\n        }\n    }\n}\n```\n\nSo `close()` is in a generated `finally`, but unlike hand-written `finally` it\nrecords a `close()` failure as a **suppressed** exception instead of discarding\nthe original. That bookkeeping is the whole point.\n",{"id":1415,"difficulty":105,"q":1416,"a":1417},"close-ordering","In what order are multiple resources closed?","In the **reverse order of declaration** — last declared is closed first. This\nmirrors how dependencies stack: a later resource often depends on an earlier\none, so it must be torn down first (like nested `finally` blocks).\n\n```java\ntry (Resource a = new Resource(\"A\");\n     Resource b = new Resource(\"B\");\n     Resource c = new Resource(\"C\")) {\n    \u002F\u002F ... use a, b, c\n}\n\u002F\u002F close order: C, then B, then A\n```\n\nThis LIFO order is guaranteed by the spec. For example, a `BufferedWriter`\nwrapping a `FileWriter` is closed before the `FileWriter` it depends on.\n",{"id":1419,"difficulty":113,"q":1420,"a":1421},"multiple-resources","How do you manage multiple resources in one try-with-resources statement?","Declare them in the parentheses **separated by semicolons**; each is closed\nautomatically. This avoids the deeply nested `try\u002Ffinally` blocks the old style\nrequired.\n\n```java\ntry (FileInputStream in = new FileInputStream(\"src.txt\");\n     FileOutputStream out = new FileOutputStream(\"dst.txt\")) {\n    in.transferTo(out);\n}   \u002F\u002F out closed first, then in — both guaranteed\n```\n\nEach resource is **independently closed**: even if closing `out` throws, the\nruntime still closes `in`. A trailing semicolon after the last resource is\nallowed but optional.\n",{"id":496,"difficulty":126,"q":497,"a":1423},"When the `try` **body throws** and a resource's `close()` **also throws**,\ntry-with-resources **propagates the body's exception** (the more useful one) and\nattaches the `close()` exception to it as a **suppressed** exception, retrievable\nvia `Throwable.getSuppressed()`.\n\n```java\ntry (var r = new FlakyResource()) {\n    throw new RuntimeException(\"body failed\");   \u002F\u002F primary\n}   \u002F\u002F r.close() throws too -> attached as suppressed\n\n\u002F\u002F caught primary:\ncatch (Exception e) {\n    for (Throwable s : e.getSuppressed())\n        System.out.println(\"suppressed: \" + s);  \u002F\u002F close's exception\n}\n```\n\nSo no exception is lost: the primary surfaces, the secondary rides along. The\nstack trace prints suppressed ones under a `Suppressed:` heading.\n",{"id":1425,"difficulty":126,"q":1426,"a":1427},"lost-exception-finally-bug","How does try-with-resources fix the \"lost exception\" bug of try\u002Ffinally?","In a hand-written `try\u002Ffinally`, if **both** the body and `close()` throw, the\n`finally`'s exception **replaces** the body's — the original failure is silently\nlost, hiding the real bug.\n\n```java\ntry {\n    throw new RuntimeException(\"REAL cause\");\n} finally {\n    throw new IOException(\"close failed\");  \u002F\u002F this WINS; \"REAL cause\" gone\n}\n```\n\nTry-with-resources reverses the priority: the **body's** exception wins and the\n`close()` exception is recorded as **suppressed** rather than thrown over it. You\nget the genuine cause as the primary, with the cleanup failure preserved\nalongside instead of erased.\n",{"id":1429,"difficulty":105,"q":1430,"a":1431},"get-add-suppressed","What are getSuppressed() and addSuppressed()?","They're the two `Throwable` methods (Java 7) behind the suppressed-exception\nmechanism. `addSuppressed(Throwable)` attaches a secondary exception to a primary\none; `getSuppressed()` returns the array of attached exceptions.\n\n```java\nThrowable[] suppressed = primaryException.getSuppressed();\n\n\u002F\u002F what the compiler-generated finally effectively calls:\nprimaryException.addSuppressed(closeException);\n```\n\nTry-with-resources calls `addSuppressed` for you automatically, but the methods\nare public so you can use them manually. You **can't** suppress a throwable into\nitself, and passing `null` throws `NullPointerException`.\n",{"id":1433,"difficulty":105,"q":1434,"a":1435},"effectively-final-resource","What is the effectively-final resource form added in Java 9?","Before Java 9 you had to **declare** the resource inside the `try` parentheses.\nJava 9 lets you reference an **already-declared variable** there, as long as it's\n`final` or **effectively final** (never reassigned after init).\n\n```java\n\u002F\u002F Java 9+: reuse an existing effectively-final variable\nBufferedReader br = new BufferedReader(new FileReader(\"a.txt\"));\ntry (br) {           \u002F\u002F no re-declaration needed\n    return br.readLine();\n}   \u002F\u002F br still closed automatically\n```\n\nThis avoids awkward redundant declarations like `try (Reader r2 = r1)`. The\nvariable must not be reassigned, or the compiler rejects it — the resource must\nbe stable so the runtime closes the right object.\n",{"id":1437,"difficulty":105,"q":1438,"a":1439},"try-with-catch-finally","Can try-with-resources have catch and finally blocks?","Yes. You can append `catch` and `finally` clauses just like a normal `try`. The\nkey ordering rule: **resources are closed first**, then the `catch`\u002F`finally`\nrun. So a `catch` sees an already-closed resource.\n\n```java\ntry (var conn = open()) {\n    conn.run();\n} catch (SQLException e) {     \u002F\u002F runs AFTER conn is closed\n    log.error(\"db error\", e);\n} finally {\n    System.out.println(\"done\"); \u002F\u002F runs LAST\n}\n```\n\nThis matters because the `catch` can handle exceptions thrown by `close()` too —\nby the time it executes, cleanup is complete and you only deal with what\npropagated out.\n",{"id":1441,"difficulty":105,"q":1442,"a":1443},"writing-custom-autocloseable","How do you write your own AutoCloseable resource?","Implement `AutoCloseable` (or `Closeable`) and put release logic in `close()`.\nMake it **idempotent** and avoid throwing from `close()` where you can.\n\n```java\nclass Timer implements AutoCloseable {\n    private final long start = System.nanoTime();\n    private boolean closed = false;\n    @Override public void close() {     \u002F\u002F narrowed: throws nothing\n        if (closed) return;             \u002F\u002F idempotent guard\n        closed = true;\n        System.out.println(\"took \" + (System.nanoTime() - start) + \"ns\");\n    }\n}\n\ntry (var t = new Timer()) { doWork(); }  \u002F\u002F prints elapsed time on exit\n```\n\nThis pattern is great for scoped concerns — timing, locks, transaction commit,\nMDC context — anything with a clear \"enter then guaranteed exit.\"\n",{"id":1445,"difficulty":126,"q":1446,"a":1447},"close-throws-exception","What happens if close() throws and the body completes normally?","If the body finishes **without** an exception, there's no primary exception to\nsuppress against, so the `close()` exception is **thrown normally** out of the\n`try` statement. It becomes the exception the caller sees.\n\n```java\ntry (var r = new FlakyResource()) {\n    \u002F\u002F body succeeds, no exception here\n}   \u002F\u002F but close() throws IOException -> THIS propagates to the caller\n```\n\nSo a successful body can still produce a failure from cleanup — which is why\n`close()` on something like a `BufferedWriter` (which flushes) genuinely matters:\na failed final flush surfaces as a real, non-suppressed exception you must handle.\n",{"id":1449,"difficulty":105,"q":1450,"a":1451},"closed-on-return","Are resources closed if the body returns early or throws?","Yes — **every** exit path closes the resources: a normal fall-through, an early\n`return`, a `break`\u002F`continue` out of the block, or a thrown exception. That\nguarantee is the entire value proposition; closing happens in the\ncompiler-generated `finally`.\n\n```java\nString first(BufferedReader br) throws IOException {\n    try (br) {\n        return br.readLine();   \u002F\u002F br is STILL closed before returning\n    }\n}\n```\n\nJust like a `finally`, the close runs before the method actually returns or the\nexception escapes. There's no code path that can leak the resource.\n",{"id":1453,"difficulty":126,"q":1454,"a":1455},"constructor-throws","What happens if a later resource's constructor throws during initialization?","Resources are initialized **left to right**. If a later resource's constructor\nthrows, the resources **already opened are closed** (in reverse order) before the\nexception propagates — no leak.\n\n```java\ntry (Resource a = new Resource(\"A\");      \u002F\u002F opens OK\n     Resource b = openThatThrows();        \u002F\u002F throws here\n     Resource c = new Resource(\"C\")) {     \u002F\u002F never created\n    ...\n}\n\u002F\u002F a IS closed; c was never opened; the constructor's exception propagates\n```\n\nThis is exactly what the nested-`try\u002Ffinally` style struggled to get right by\nhand. The runtime closes only what was successfully created, in LIFO order.\n",{"id":1457,"difficulty":105,"q":1458,"a":1459},"vs-try-finally-table","Compare try-with-resources with try\u002Ffinally.","Try-with-resources is the modern replacement; reach for manual `try\u002Ffinally`\nonly for cleanup that **isn't a closeable resource**.\n\n| Aspect | try-with-resources | try\u002Ffinally |\n| --- | --- | --- |\n| Closes resource | automatic | manual `close()` |\n| Both throw | body wins, close **suppressed** | finally wins, body **lost** |\n| Null safety | handled by compiler | manual null check |\n| Multiple resources | one statement, LIFO | nested blocks |\n| Requires | `AutoCloseable` type | any cleanup code |\n\n```java\ntry (var r = open()) { use(r); }    \u002F\u002F preferred for resources\n```\n\nUse `try\u002Ffinally` for non-resource teardown (resetting a flag, restoring thread\nstate); use try-with-resources for anything implementing `AutoCloseable`.\n",{"id":1461,"difficulty":105,"q":1462,"a":1463},"null-resource","What happens if a resource expression evaluates to null?","Nothing breaks. The generated code **null-checks** each resource before calling\n`close()`, so a `null` resource is simply skipped — no `NullPointerException` at\nclose time.\n\n```java\ntry (Reader r = mightReturnNull()) {   \u002F\u002F returns null\n    if (r != null) r.read();           \u002F\u002F your own guard still needed for use\n}   \u002F\u002F close() is NOT called on null — safe\n```\n\nNote the guard only protects the **close**, not your use of the resource inside\nthe body — dereferencing a `null` `r` there still throws. This null-tolerance is\none of the boilerplate cases the old manual `if (x != null) x.close()` pattern\nhad to handle by hand.\n",{"id":1465,"difficulty":126,"q":1466,"a":1467},"lock-pattern","Why is try-with-resources not a drop-in replacement for lock\u002Funlock?","A `Lock` is **not** `AutoCloseable`, and more importantly the lock must be\n**acquired before** the `try`, not in it — otherwise a failure to acquire would\nstill trigger an unlock. The correct idiom keeps `lock()` outside and `unlock()`\nin a `finally`.\n\n```java\nlock.lock();                  \u002F\u002F acquire BEFORE try\ntry {\n    criticalSection();\n} finally {\n    lock.unlock();            \u002F\u002F try\u002Ffinally, NOT try-with-resources\n}\n```\n\nYou *can* wrap a lock in a small `AutoCloseable` helper that unlocks in `close()`,\nbut you must still acquire before entering the `try`. This is a classic interview\n\"when is try-with-resources the wrong tool\" question — its answer is **manual\nacquisition + try\u002Ffinally**.\n",{"description":103},"Java try-with-resources interview questions — AutoCloseable and Closeable, automatic resource management, suppressed exceptions, close ordering, the effectively-final form, and comparison with finally.","java\u002Fexceptions\u002Ftry-with-resources","V4eaAnIVzYq7xnljOMwEir2Z06qpo3K1NxGnW9cJ1RQ",{"id":1473,"title":1474,"body":1475,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":1479,"navigation":108,"order":29,"path":1480,"questions":1481,"questionsCount":1370,"related":250,"seo":1572,"seoDescription":1573,"stem":1574,"subtopic":1474,"topic":20,"topicSlug":21,"updated":809,"__hash__":1575},"qa\u002Fjava\u002Ffundamentals\u002Fstrings.md","Strings",{"type":100,"value":1476,"toc":1477},[],{"title":103,"searchDepth":29,"depth":29,"links":1478},[],{},"\u002Fjava\u002Ffundamentals\u002Fstrings",[1482,1485,1488,1492,1496,1500,1504,1507,1511,1515,1519,1523,1527,1531,1535,1539,1543,1547,1551,1554,1558,1560,1564,1568],{"id":591,"difficulty":105,"q":1483,"a":1484},"Why are Strings immutable in Java, and what does that buy you?","A `String` wraps a `private final` array of characters that is never exposed\nor modified after construction; every \"modifying\" method returns a **new**\n`String`. Immutability buys four things interviewers want to hear:\n\n- **Security** — a path, URL, or username can't be changed after a check.\n- **Caching \u002F pooling** — identical literals can be shared safely.\n- **Thread safety** — an immutable object needs no synchronization.\n- **Hashcode caching** — the hash is computed once and can never go stale,\n  making `String` an ideal `HashMap` key.\n\n```java\nString s = \"hello\";\ns.concat(\" world\");      \u002F\u002F returns a NEW String, discarded here\nSystem.out.println(s);   \u002F\u002F \"hello\" — s itself is unchanged\ns = s.toUpperCase();     \u002F\u002F reassign the reference to the new String\n```\n\nThe trade-off is garbage: heavy string building creates throwaway objects,\nwhich is exactly why `StringBuilder` exists.\n",{"id":595,"difficulty":105,"q":1486,"a":1487},"What is the String constant pool?","The string pool (a.k.a. the **intern pool**) is a special area where the JVM\nstores **one shared copy** of each distinct string **literal**. Two identical\nliterals refer to the same pooled object, saving memory. Strings built with\n`new` are *not* pooled — they create a fresh heap object.\n\n```java\nString a = \"hi\";              \u002F\u002F pooled\nString b = \"hi\";              \u002F\u002F same pooled object\nString c = new String(\"hi\");  \u002F\u002F new heap object, NOT pooled\na == b   \u002F\u002F true  — same pooled reference\na == c   \u002F\u002F false — different objects\n```\n\nImmutability is what makes pooling safe — since no one can mutate `\"hi\"`,\nit's harmless to share it everywhere. Since Java 7 the pool lives on the\nheap (not PermGen), so it's subject to normal garbage collection.\n",{"id":1489,"difficulty":105,"q":1490,"a":1491},"literal-vs-new","What is the difference between String s = \"x\" and new String(\"x\")?","A **literal** is resolved at class-load time and points at the **pooled**\nobject — repeated literals share one instance. **`new String(\"x\")`** forces a\nbrand-new object on the heap *plus* puts `\"x\"` in the pool, so it can create\n**two** objects and is almost always wasteful.\n\n```java\nString a = \"x\";            \u002F\u002F 1 pooled object\nString b = \"x\";            \u002F\u002F reuses the pooled object\nString c = new String(\"x\"); \u002F\u002F 1 new heap object (+ \"x\" already pooled)\na == b          \u002F\u002F true\na == c          \u002F\u002F false — c is a distinct object\na.equals(c)     \u002F\u002F true  — same characters\n```\n\nRule: never write `new String(\"literal\")` — it defeats pooling for no benefit.\n",{"id":1493,"difficulty":126,"q":1494,"a":1495},"intern","What does the intern() method do?","`intern()` returns the **canonical pooled copy** of a string: if an equal\nstring is already in the pool, you get that reference; otherwise the string\nis added to the pool and that reference is returned. It lets you force\n`==` to work on computed strings.\n\n```java\nString a = \"hi\";\nString c = new String(\"hi\");\na == c            \u002F\u002F false\na == c.intern()   \u002F\u002F true — intern() returns the pooled \"hi\"\n\nString built = (\"h\" + new String(\"i\")).intern();\na == built        \u002F\u002F true\n```\n\nUse it sparingly: interning huge numbers of unique strings just fills the\npool and can hurt more than it helps. It's mainly useful for deduplicating a\nbounded set of repeated values to save memory.\n",{"id":1497,"difficulty":113,"q":1498,"a":1499},"eqeq-vs-equals","What is the difference between == and .equals() for Strings?","`==` compares **references** (do both variables point to the *same* object?),\nwhile `.equals()` compares the **characters**. For strings you almost always\nwant `.equals()` — `==` only \"works\" by accident when both operands happen to\nbe the same pooled literal.\n\n```java\nString a = \"hi\";\nString b = new String(\"hi\");\na == b         \u002F\u002F false — different objects\na.equals(b)    \u002F\u002F true  — same characters\n\nString c = \"hi\";\na == c         \u002F\u002F true  — both the pooled literal (coincidence, don't rely on it)\n```\n\nThis is the single most common Java beginner bug. Always compare string\n*content* with `.equals()` (or `equalsIgnoreCase`).\n",{"id":1501,"difficulty":113,"q":1502,"a":1503},"null-safe-equals","How do you compare strings safely when one might be null?","Calling `.equals()` on a `null` reference throws **`NullPointerException`**.\nThe classic trick is to put the **known constant on the left**, or use the\nnull-safe `Objects.equals`.\n\n```java\nString input = maybeNull();\n\ninput.equals(\"yes\");          \u002F\u002F NPE if input is null\n\"yes\".equals(input);          \u002F\u002F safe — false when input is null\n\nObjects.equals(input, \"yes\"); \u002F\u002F safe both ways\n```\n\nThe \"Yoda condition\" (`\"yes\".equals(input)`) is the idiomatic fix; reach for\n`Objects.equals(a, b)` when *either* side could be null.\n",{"id":1505,"difficulty":105,"q":600,"a":1506},"stringbuilder-vs-buffer","| Type | Mutable? | Thread-safe? | Use when |\n| ---- | -------- | ------------ | -------- |\n| `String` | no | yes (immutable) | fixed text, map keys |\n| `StringBuilder` | yes | no | building strings (the default) |\n| `StringBuffer` | yes | yes (synchronized) | shared across threads (rare) |\n\n`StringBuilder` and `StringBuffer` share the **same API**; the only\ndifference is `StringBuffer`'s methods are `synchronized`, which makes it\nslower.\n\n```java\nStringBuilder sb = new StringBuilder();\nsb.append(\"a\").append(1).append(true); \u002F\u002F fluent, mutates in place\nString result = sb.toString();         \u002F\u002F \"a1true\"\n```\n\nPrefer **`StringBuilder`** by default; you rarely need `StringBuffer` because\nshared mutable string state across threads is uncommon (and usually better\nhandled with a local builder per thread).\n",{"id":1508,"difficulty":105,"q":1509,"a":1510},"concat-in-loop","Why is concatenating strings in a loop with + a problem?","Because `String` is immutable, `s += part` allocates a **new** `String` (and\ncopies all existing characters) on **every iteration** — overall **O(n²)**\nwork and a pile of garbage. A single `StringBuilder` reuses one growing\nbuffer for amortized **O(n)**.\n\n```java\n\u002F\u002F O(n²) — a new String each iteration\nString r = \"\";\nfor (String p : parts) r += p;\n\n\u002F\u002F O(n) — one reused buffer\nStringBuilder sb = new StringBuilder();\nfor (String p : parts) sb.append(p);\nString r2 = sb.toString();\n```\n\nThe compiler optimizes a *single* `a + b + c` expression into `StringBuilder`\ncalls automatically — the problem is concatenation **inside a loop**, which it\ncannot collapse.\n",{"id":1512,"difficulty":126,"q":1513,"a":1514},"plus-compiles-to","What does the + operator on strings compile to?","Historically `javac` rewrote `a + b + c` into a chain of\n`new StringBuilder().append(a).append(b).append(c).toString()`. Since\n**Java 9**, it instead emits an **`invokedynamic`** call bound to\n`StringConcatFactory` (\"indified string concatenation\"), letting the JVM pick\nthe optimal strategy at runtime.\n\n```java\nString s = \"x\" + n + \"y\";\n\u002F\u002F pre-9 : new StringBuilder().append(\"x\").append(n).append(\"y\").toString()\n\u002F\u002F 9+    : invokedynamic -> StringConcatFactory.makeConcatWithConstants(...)\n```\n\nPractical takeaway is unchanged: a single `+` expression is fine and fast; a\n`+=` accumulation **inside a loop** still creates one object per iteration —\nuse `StringBuilder` there.\n",{"id":1516,"difficulty":113,"q":1517,"a":1518},"equalsignorecase-compareto","What is the difference between equals, equalsIgnoreCase and compareTo?","- **`equals`** — case-**sensitive** content equality, returns `boolean`.\n- **`equalsIgnoreCase`** — same, but ignores case.\n- **`compareTo`** — **lexicographic ordering**, returns an `int`: negative if\n  this string sorts before the argument, `0` if equal, positive if after.\n\n```java\n\"abc\".equals(\"ABC\")            \u002F\u002F false\n\"abc\".equalsIgnoreCase(\"ABC\")  \u002F\u002F true\n\"apple\".compareTo(\"banana\")    \u002F\u002F negative (a \u003C b)\n\"abc\".compareTo(\"abc\")         \u002F\u002F 0\n\"abc\".compareToIgnoreCase(\"ABC\") \u002F\u002F 0\n```\n\nUse `equals`\u002F`equalsIgnoreCase` for \"are these the same?\" and `compareTo`\n(or `String.CASE_INSENSITIVE_ORDER`) when **sorting**.\n",{"id":1520,"difficulty":105,"q":1521,"a":1522},"substring","How does substring work and what are its gotchas?","`substring(begin)` returns from `begin` to the end; `substring(begin, end)`\nreturns `[begin, end)` — **`end` is exclusive**. Indices out of range throw\n`StringIndexOutOfBoundsException`.\n\n```java\n\"interview\".substring(0, 5);  \u002F\u002F \"inter\" — chars 0..4\n\"interview\".substring(5);     \u002F\u002F \"view\"\n\"abc\".substring(3);           \u002F\u002F \"\"  (begin == length is legal)\n\"abc\".substring(1, 1);        \u002F\u002F \"\"  (begin == end)\n\"abc\".substring(2, 1);        \u002F\u002F exception — end \u003C begin\n```\n\nModern note: since Java 7u6 `substring` **copies** the chars into a new array\n(older JVMs shared the backing array, which could leak the whole parent\nstring), so there's no longer a hidden memory-retention trap.\n",{"id":1524,"difficulty":113,"q":1525,"a":1526},"indexof-charat-contains","How do indexOf, charAt and contains work?","- **`charAt(i)`** — the `char` at index `i` (0-based); out of range throws\n  `StringIndexOutOfBoundsException`.\n- **`indexOf(x)`** — first index of a char or substring, or **`-1`** if absent.\n- **`contains(seq)`** — `boolean`, true if the substring occurs.\n\n```java\nString s = \"banana\";\ns.charAt(1);          \u002F\u002F 'a'\ns.indexOf('a');       \u002F\u002F 1   (first match)\ns.indexOf('a', 2);    \u002F\u002F 3   (start searching from index 2)\ns.lastIndexOf('a');   \u002F\u002F 5\ns.indexOf(\"xyz\");     \u002F\u002F -1  (not found)\ns.contains(\"nan\");    \u002F\u002F true\n```\n\nRemember `indexOf` returns **−1**, not throws, when nothing matches — guard\nwith `if (i >= 0)` before using the result as an index.\n",{"id":1528,"difficulty":105,"q":1529,"a":1530},"split","How does String.split work and what are its surprises?","`split(regex)` breaks a string on a **regular expression** (not a literal!)\nand returns a `String[]`. Two surprises: it **drops trailing empty strings**\nby default, and regex metacharacters must be escaped.\n\n```java\n\"a,b,c\".split(\",\")         \u002F\u002F [\"a\", \"b\", \"c\"]\n\"a,b,,\".split(\",\")         \u002F\u002F [\"a\", \"b\"]  — trailing empties removed\n\"a,b,,\".split(\",\", -1)     \u002F\u002F [\"a\", \"b\", \"\", \"\"] — limit -1 keeps them\n\"a.b.c\".split(\".\")         \u002F\u002F [] — \".\" matches ANY char; needs \"\\\\.\"\n\"a.b.c\".split(\"\\\\.\")       \u002F\u002F [\"a\", \"b\", \"c\"]\n```\n\nPass a negative **limit** to keep trailing blanks, and escape `. | ( ) [ ] \\`\netc. For a plain delimiter use `Pattern.quote(delim)`.\n",{"id":1532,"difficulty":105,"q":1533,"a":1534},"replace-vs-replaceall","What is the difference between replace and replaceAll?","**`replace`** works on **literal** text (a `char` or `CharSequence`) and\nreplaces every occurrence. **`replaceAll`** (and `replaceFirst`) take a\n**regex** as the pattern. Both return a new string — `String` is immutable.\n\n```java\n\"a.b.c\".replace(\".\", \"-\")      \u002F\u002F \"a-b-c\"  — literal dot\n\"a.b.c\".replaceAll(\".\", \"-\")   \u002F\u002F \"-----\"  — \".\" is regex \"any char\"!\n\"a.b.c\".replaceAll(\"\\\\.\", \"-\") \u002F\u002F \"a-b-c\"  — escaped dot\n\"a1b2\".replaceAll(\"\\\\d\", \"#\")  \u002F\u002F \"a#b#\"   — regex digit class\n```\n\nIf you don't need regex, prefer `replace` — it's faster and avoids the\n\"every char got replaced\" trap.\n",{"id":1536,"difficulty":105,"q":1537,"a":1538},"trim-vs-strip","What is the difference between trim() and strip()?","Both remove leading and trailing whitespace, but **`trim`** (legacy) only\nstrips characters `\u003C= U+0020` (ASCII space and control chars), while\n**`strip`** (Java 11+) is **Unicode-aware** and removes all Unicode\nwhitespace. `strip` also has one-sided variants.\n\n```java\n\"  hi  \".trim()              \u002F\u002F \"hi\"\n\" hi \".trim()      \u002F\u002F \" hi \" — thin space NOT removed\n\" hi \".strip()     \u002F\u002F \"hi\"             — Unicode-aware\n\" hi \".stripLeading()        \u002F\u002F \"hi \"\n\" hi \".stripTrailing()       \u002F\u002F \" hi\"\n```\n\nPrefer **`strip`** on modern Java for correct handling of non-ASCII\nwhitespace; `trim` is fine for plain ASCII input.\n",{"id":1540,"difficulty":113,"q":1541,"a":1542},"isblank-isempty","What is the difference between isEmpty() and isBlank()?","**`isEmpty()`** is true only when the length is `0`. **`isBlank()`** (Java\n11+) is true when the string is empty **or** contains only whitespace.\n\n```java\n\"\".isEmpty()      \u002F\u002F true\n\"   \".isEmpty()   \u002F\u002F false — it has characters\n\"   \".isBlank()   \u002F\u002F true  — only whitespace\n\"x\".isBlank()     \u002F\u002F false\n```\n\nNeither is null-safe, so check for `null` first (or use a helper like\n`StringUtils.isBlank`). Use `isBlank` when \"all-spaces\" should count as\n\"empty\" — e.g. validating user input.\n",{"id":1544,"difficulty":126,"q":1545,"a":1546},"char-passwords","Why use char[] instead of String for passwords?","A `String` is **immutable** and may sit in the **pool**, so you cannot clear\nits contents — the password lingers in memory until garbage collected and\ncould surface in a heap dump. A **`char[]`** can be **explicitly wiped**\nright after use.\n\n```java\nchar[] pw = readPassword();\ntry {\n    authenticate(pw);\n} finally {\n    Arrays.fill(pw, '\\0'); \u002F\u002F overwrite — minimizes the exposure window\n}\n```\n\nThis is why `JPasswordField.getPassword()` and `Console.readPassword()`\nreturn `char[]`. Strings also risk accidental logging via `toString()`,\nwhich `char[]` avoids.\n",{"id":1548,"difficulty":105,"q":1549,"a":1550},"string-conversions","How do you convert between String, char[] and byte[]?","Use `toCharArray()` \u002F the `String(char[])` constructor for characters, and\n`getBytes(charset)` \u002F `new String(bytes, charset)` for bytes. **Always\nspecify a charset** for byte conversions to avoid platform-default surprises.\n\n```java\nchar[] chars = \"hi\".toCharArray();        \u002F\u002F ['h','i']\nString fromChars = new String(chars);      \u002F\u002F \"hi\"\nString fromChars2 = String.valueOf(chars); \u002F\u002F \"hi\"\n\nbyte[] bytes = \"hi\".getBytes(StandardCharsets.UTF_8);\nString fromBytes = new String(bytes, StandardCharsets.UTF_8); \u002F\u002F \"hi\"\n```\n\nOmitting the charset uses the JVM default encoding, which differs across\nmachines and causes the classic \"works on my box\" mojibake bug — pass\n`StandardCharsets.UTF_8` explicitly.\n",{"id":1552,"difficulty":113,"q":680,"a":1553},"string-to-number","Parse with the wrapper classes' static methods; produce text with\n`String.valueOf` or concatenation. `parseXxx` returns a **primitive**,\n`valueOf` a **wrapper object**.\n\n```java\nint n     = Integer.parseInt(\"42\");        \u002F\u002F primitive int\ndouble d  = Double.parseDouble(\"3.14\");\nInteger w = Integer.valueOf(\"42\");          \u002F\u002F Integer object\nString s  = String.valueOf(42);             \u002F\u002F \"42\"\nString s2 = \"\" + 42;                         \u002F\u002F \"42\" via concatenation\n```\n\nA malformed string throws **`NumberFormatException`**, so validate or\ntry\u002Fcatch when parsing untrusted input.\n",{"id":1555,"difficulty":105,"q":1556,"a":1557},"format-and-join","How do String.format, String.join and repeat work?","- **`String.format`** builds a string from a printf-style template.\n- **`String.join`** glues elements with a delimiter (Java 8+).\n- **`repeat`** duplicates a string `n` times (Java 11+).\n\n```java\nString.format(\"%s is %d\", \"Ada\", 36);   \u002F\u002F \"Ada is 36\"\nString.format(\"%.2f\", 3.14159);          \u002F\u002F \"3.14\"\nString.join(\"-\", \"a\", \"b\", \"c\");          \u002F\u002F \"a-b-c\"\nString.join(\",\", List.of(\"x\", \"y\"));      \u002F\u002F \"x,y\"\n\"ab\".repeat(3);                            \u002F\u002F \"ababab\"\n```\n\n`String.join` is the clean way to build delimiter-separated output without a\ntrailing-comma loop; `format` is handy but slower than direct concatenation\nfor hot paths.\n",{"id":695,"difficulty":113,"q":696,"a":1559},"Text blocks (Java 15+) are multi-line string literals delimited by triple\nquotes `\"\"\"`. They preserve line breaks and let you write JSON, SQL, or HTML\nwithout escaping quotes or concatenating lines.\n\n```java\nString json = \"\"\"\n    {\n      \"name\": \"Ada\",\n      \"role\": \"engineer\"\n    }\n    \"\"\";\n```\n\nIncidental leading whitespace is stripped relative to the closing delimiter's\nindentation, and the result is an ordinary `String` — it's pooled and supports\nevery `String` method. Use `\\` at line end to suppress a newline.\n",{"id":1561,"difficulty":105,"q":1562,"a":1563},"switch-on-string","How does switch on a String work under the hood?","Since Java 7 you can `switch` on a `String`. The compiler implements it in\ntwo steps: it switches on the string's **`hashCode()`** (an `int` switch),\nthen guards each matched bucket with an **`.equals()`** check to handle hash\ncollisions. So it is null-sensitive and case-sensitive.\n\n```java\nswitch (cmd) {\n    case \"start\" -> run();\n    case \"stop\"  -> halt();\n    default      -> usage();\n}\n\u002F\u002F a null cmd throws NullPointerException — switch calls cmd.hashCode()\n```\n\nBecause matching is by `equals`, the labels are exact and case-sensitive;\nnormalize with `toLowerCase()` first if you need case-insensitive matching.\n",{"id":1565,"difficulty":126,"q":1566,"a":1567},"string-hashcode","How is a String's hashCode computed and why is it cached?","`String.hashCode()` uses the polynomial formula\n`s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]`, accumulated in an `int`.\nBecause the string is **immutable**, the result is computed **once** and\nstored in a `private int hash` field, then returned on every later call.\n\n```java\n\"Aa\".hashCode()  \u002F\u002F 2112\n\"BB\".hashCode()  \u002F\u002F 2112 — famous collision (same hash, not equal)\n```\n\nThe constant `31` is an odd prime that the JVM can optimize to\n`(h \u003C\u003C 5) - h`. Caching is safe precisely *because* the contents can never\nchange — one of the concrete payoffs of immutability and why `String` is the\ngo-to `HashMap` key.\n",{"id":1569,"difficulty":105,"q":1570,"a":1571},"chars-stream","How do you iterate or process the characters of a String?","Classic options are an indexed loop with `charAt`, or `toCharArray()` with a\nfor-each. Java 8 added **`chars()`**, an `IntStream` of code units, for a\nfunctional style.\n\n```java\nString s = \"abc\";\nfor (int i = 0; i \u003C s.length(); i++) {   \u002F\u002F indexed\n    char c = s.charAt(i);\n}\nfor (char c : s.toCharArray()) { }        \u002F\u002F for-each over a copy\n\nlong vowels = s.chars()                    \u002F\u002F IntStream of code units\n    .filter(c -> \"aeiou\".indexOf(c) >= 0)\n    .count();\n```\n\n`chars()` yields `int` code *units*; for full Unicode (emoji \u002F supplementary\ncharacters) use `codePoints()` instead, which combines surrogate pairs.\n",{"description":103},"Java String interview questions — String immutability, the string pool and intern(), == vs equals, String vs StringBuilder vs StringBuffer, concatenation performance, and common String API methods.","java\u002Ffundamentals\u002Fstrings","JO-iZQ8XInhM-XwQLjKVpyi-5Ylro-3l0QziRdncVGs",{"id":1577,"title":1578,"body":1579,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":1583,"navigation":108,"order":29,"path":1584,"questions":1585,"questionsCount":904,"related":250,"seo":1670,"seoDescription":1671,"stem":1672,"subtopic":1673,"topic":37,"topicSlug":39,"updated":809,"__hash__":1674},"qa\u002Fjava\u002Fgenerics\u002Fwildcards-bounds.md","Wildcards Bounds",{"type":100,"value":1580,"toc":1581},[],{"title":103,"searchDepth":29,"depth":29,"links":1582},[],{},"\u002Fjava\u002Fgenerics\u002Fwildcards-bounds",[1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650,1654,1658,1662,1666],{"id":1587,"difficulty":105,"q":1588,"a":1589},"unbounded-wildcard","What is the unbounded wildcard \u003C?> and what does it mean?","The **unbounded wildcard** `\u003C?>` means \"a `List` of **some unknown type**\" —\nyou don't know or care which. It makes a generic method work over collections\nof *any* element type while staying type-safe, unlike a raw type.\n\n```java\nstatic void printAll(List\u003C?> list) {        \u002F\u002F any element type\n  for (Object o : list) System.out.println(o); \u002F\u002F safe: everything is an Object\n}\nprintAll(List.of(1, 2, 3));      \u002F\u002F List\u003CInteger> ok\nprintAll(List.of(\"a\", \"b\"));     \u002F\u002F List\u003CString> ok\n```\n\nBecause the element type is unknown, you **can read elements as `Object`** but\n**can't add** anything (except `null`) — the compiler can't prove your value\nmatches the hidden type. Use `\u003C?>` when the method body doesn't depend on the\nelement type at all.\n",{"id":1591,"difficulty":126,"q":1592,"a":1593},"list-wildcard-vs-object-vs-raw","What is the difference between List\u003C?>, List\u003CObject> and a raw List?","They look similar but behave very differently:\n\n| Declaration | Accepts | Can add? | Type-safe? |\n| ----------- | ------- | -------- | ---------- |\n| `List\u003C?>` | any `List\u003CX>` | only `null` | yes |\n| `List\u003CObject>` | only `List\u003CObject>` | any object | yes |\n| `List` (raw) | any `List` | anything (unchecked) | no — legacy |\n\n```java\nList\u003CString> strs = new ArrayList\u003C>();\nList\u003C?> a = strs;        \u002F\u002F ok — unknown element type\nList\u003CObject> b = strs;   \u002F\u002F compile error — not the same type\nList c = strs;           \u002F\u002F ok but unchecked warnings; defeats generics\n```\n\n`List\u003CObject>` is a concrete type that only matches `List\u003CObject>`. `List\u003C?>`\nmatches *every* parameterization but is read-only. The **raw** `List` exists\nonly for pre-generics compatibility — it disables type checking, so avoid it.\n",{"id":1595,"difficulty":105,"q":1596,"a":1597},"upper-bounded-wildcard","What is an upper-bounded wildcard \u003C? extends T>?","`\u003C? extends T>` means \"some **unknown subtype** of `T`\" — it sets an **upper\nbound**. It's used when you want to **read** `T` values out of a structure but\ndon't need to know the exact subtype.\n\n```java\nstatic double sum(List\u003C? extends Number> nums) { \u002F\u002F Number or any subtype\n  double total = 0;\n  for (Number n : nums) total += n.doubleValue(); \u002F\u002F safe: all are Numbers\n  return total;\n}\nsum(List.of(1, 2, 3));        \u002F\u002F List\u003CInteger> ok\nsum(List.of(1.5, 2.5));       \u002F\u002F List\u003CDouble> ok\n```\n\nEvery element is guaranteed to be **at least a `T`**, so reading as `T` is\nsafe. This is the **producer** side — the structure produces `T`s for you to\nconsume.\n",{"id":1599,"difficulty":126,"q":1600,"a":1601},"why-cant-add-extends","Why can't you add to a List\u003C? extends Number>?","Because the compiler knows the list is `List\u003CSomeSubtypeOfNumber>` but **not\nwhich** subtype. It could be `List\u003CInteger>`, `List\u003CDouble>`, or anything else —\nso adding *any* concrete value might violate the real element type.\n\n```java\nList\u003C? extends Number> nums = new ArrayList\u003CInteger>();\nnums.add(1);        \u002F\u002F compile error — what if it's really List\u003CDouble>?\nnums.add(1.5);      \u002F\u002F compile error — what if it's really List\u003CInteger>?\nnums.add(null);     \u002F\u002F the only legal add — null fits any type\nNumber n = nums.get(0); \u002F\u002F reading is fine — guaranteed to be a Number\n```\n\nThe list becomes effectively **read-only** for element types. The rule:\n`extends` wildcards are for **getting**, not putting.\n",{"id":1603,"difficulty":105,"q":1604,"a":1605},"lower-bounded-wildcard","What is a lower-bounded wildcard \u003C? super T>?","`\u003C? super T>` means \"some **unknown supertype** of `T`\" — it sets a **lower\nbound**. It's used when you want to **write** `T` values *into* a structure.\n\n```java\nstatic void addNumbers(List\u003C? super Integer> list) { \u002F\u002F Integer or any supertype\n  list.add(1);          \u002F\u002F safe — an Integer fits a List of Integer-or-wider\n  list.add(2);\n}\naddNumbers(new ArrayList\u003CInteger>()); \u002F\u002F ok\naddNumbers(new ArrayList\u003CNumber>());  \u002F\u002F ok — Integer fits a Number list\naddNumbers(new ArrayList\u003CObject>());  \u002F\u002F ok — Integer fits an Object list\n```\n\nWhatever the real type is, it's `Integer` or wider, so an `Integer` is always a\nvalid element. This is the **consumer** side — the structure consumes the `T`s\nyou supply.\n",{"id":1607,"difficulty":126,"q":1608,"a":1609},"read-from-super-wildcard","What can you read back from a List\u003C? super T>?","Only **`Object`**. The compiler knows the list holds *some supertype* of `T`,\nbut the widest guaranteed common type of any supertype is `Object`, so that's\nall a `get` can be typed as.\n\n```java\nList\u003C? super Integer> list = new ArrayList\u003CNumber>();\nlist.add(42);              \u002F\u002F writing Integers is fine\nObject o = list.get(0);    \u002F\u002F ok — only Object is guaranteed\nInteger i = list.get(0);   \u002F\u002F compile error — could be a Number\u002FObject list\n```\n\nSo `super` wildcards are primarily for **putting in**; reading gives you back\nuntyped `Object`. This asymmetry with `extends` is exactly what PECS captures.\n",{"id":1611,"difficulty":126,"q":1612,"a":1613},"pecs-principle","What is the PECS principle?","**PECS** = **Producer Extends, Consumer Super**. When a parameter **produces**\n`T`s for you (you read from it), use `\u003C? extends T>`. When it **consumes** `T`s\nyou give it (you write to it), use `\u003C? super T>`. The canonical example is a\n`copy` method:\n\n```java\n\u002F\u002F src PRODUCES elements -> extends; dest CONSUMES elements -> super\nstatic \u003CT> void copy(List\u003C? extends T> src, List\u003C? super T> dest) {\n  for (T t : src) dest.add(t);   \u002F\u002F read from src, write to dest\n}\nList\u003CInteger> ints = List.of(1, 2, 3);\nList\u003CNumber> dst = new ArrayList\u003C>();\ncopy(ints, dst);                 \u002F\u002F Integer producer -> Number consumer\n```\n\nThis is how `Collections.copy` is actually declared. PECS maximizes API\nflexibility: callers can pass a wider range of list types on each side.\n",{"id":1615,"difficulty":126,"q":1616,"a":1617},"bounded-type-param-vs-wildcard","When should you use a bounded type parameter \u003CT extends Number> vs a wildcard?","Use a **bounded type parameter** when you need to **name the type** — to refer\nto it more than once, relate two arguments, or use it in the return type. Use a\n**wildcard** when the type is used only **once** and you never need to name it.\n\n```java\n\u002F\u002F type parameter: the SAME T links input and return\nstatic \u003CT extends Number> T firstOf(List\u003CT> list) { return list.get(0); }\n\n\u002F\u002F wildcard: type used once, never named\nstatic double sumOf(List\u003C? extends Number> list) { \u002F* ... *\u002F return 0; }\n```\n\nA good rule: if a wildcard would force you to invent a helper just to name the\ntype, use a type parameter instead. Otherwise prefer wildcards in API\nparameters — they read more cleanly to callers.\n",{"id":1619,"difficulty":126,"q":1620,"a":1621},"multiple-bounds","How do multiple bounds \u003CT extends A & B> work?","A type parameter can require **several bounds** joined by `&`, meaning `T` must\nsatisfy **all** of them. At most **one can be a class**, and if present it must\ncome **first**; the rest must be interfaces.\n\n```java\n\u002F\u002F T must be both Comparable AND Serializable\nstatic \u003CT extends Comparable\u003CT> & Serializable> T maxOf(T a, T b) {\n  return a.compareTo(b) >= 0 ? a : b; \u002F\u002F can call Comparable methods on T\n}\n\n\u002F\u002F class first, then interfaces:\nstatic \u003CT extends Number & Comparable\u003CT>> T pick(T x) { return x; }\n```\n\nWithin the method `T` exposes the members of **all** bounds. Wildcards, by\ncontrast, allow only a **single** bound (`\u003C? extends A>`), so multiple bounds\nrequire a named type parameter.\n",{"id":1623,"difficulty":126,"q":1624,"a":1625},"recursive-bound","Why does \u003CT extends Comparable\u003CT>> appear so often?","This is a **recursive (self-referential) type bound** — `T` must be comparable\n**to itself**. It captures the idea \"this type knows how to order its own\ninstances,\" which is exactly what sorting and min\u002Fmax need.\n\n```java\nstatic \u003CT extends Comparable\u003CT>> T max(List\u003CT> list) {\n  T best = list.get(0);\n  for (T t : list)\n    if (t.compareTo(best) > 0) best = t; \u002F\u002F t.compareTo(T) is type-safe\n  return best;\n}\nmax(List.of(3, 1, 2));        \u002F\u002F T = Integer, Integer implements Comparable\u003CInteger>\n```\n\nWithout the recursion you couldn't safely call `compareTo` with a `T` argument.\nThe real `Collections.max` uses `\u003CT extends Comparable\u003C? super T>>` — slightly\nlooser so a subtype can reuse an ancestor's comparison.\n",{"id":1627,"difficulty":126,"q":1628,"a":1629},"wildcard-capture","What is wildcard capture and the capture-helper pattern?","**Wildcard capture** is the compiler giving the unknown type of a `\u003C?>` a\ntemporary name (shown in errors as `CAP#1`). Sometimes you need to *name* that\ntype to operate on it — the fix is a private **capture helper** generic method\nthat captures the wildcard into a real type variable.\n\n```java\n\u002F\u002F fails: compiler won't prove list.get(i) matches list.set(j, ...)\nstatic void swap(List\u003C?> list, int i, int j) {\n  swapHelper(list, i, j);                 \u002F\u002F delegate to capture the wildcard\n}\nprivate static \u003CT> void swapHelper(List\u003CT> list, int i, int j) {\n  T tmp = list.get(i);                    \u002F\u002F now there is a concrete T\n  list.set(i, list.get(j));\n  list.set(j, tmp);\n}\n```\n\nThe public method keeps the clean `\u003C?>` signature; the helper captures the\nwildcard as `T` so the body type-checks.\n",{"id":1631,"difficulty":126,"q":1632,"a":1633},"array-covariance-generic-invariance","Why are arrays covariant but generics invariant?","Arrays are **covariant**: `String[]` *is a* `Object[]`. Generics are\n**invariant**: `List\u003CString>` is **not** a `List\u003CObject>`. Generics chose\ninvariance for **compile-time safety** — array covariance defers the check to\nruntime and can blow up.\n\n```java\nObject[] arr = new String[3];\narr[0] = 42;          \u002F\u002F compiles, throws ArrayStoreException at RUNTIME\n\nList\u003CObject> list = new ArrayList\u003CString>(); \u002F\u002F compile error — caught early\n```\n\nBecause generics are erased at runtime there's no `ArrayStore` check to fall\nback on, so the language forbids the unsafe assignment up front. **Wildcards**\nthen restore the lost flexibility safely (`List\u003C? extends Object>` accepts a\n`List\u003CString>` but won't let you put the wrong thing in).\n",{"id":1635,"difficulty":105,"q":1636,"a":1637},"wildcards-restore-flexibility","How do wildcards restore the flexibility lost to invariance?","Invariance means `List\u003CInteger>` isn't a `List\u003CNumber>`, so a method taking\n`List\u003CNumber>` would reject an `Integer` list. A **wildcard** widens the\nparameter to accept a family of types while staying safe.\n\n```java\nstatic double total(List\u003CNumber> list) { \u002F* ... *\u002F return 0; }\ntotal(new ArrayList\u003CInteger>());      \u002F\u002F compile error — invariance\n\nstatic double total2(List\u003C? extends Number> list) { \u002F* ... *\u002F return 0; }\ntotal2(new ArrayList\u003CInteger>());     \u002F\u002F ok — wildcard accepts subtypes\ntotal2(new ArrayList\u003CDouble>());      \u002F\u002F ok\n```\n\nSo wildcards are the bridge between strict invariance and the polymorphism you\nactually want — you opt into covariance (`extends`) or contravariance (`super`)\nexactly where it's safe.\n",{"id":1639,"difficulty":126,"q":1640,"a":1641},"collections-max-signature","Why is Collections.max declared with both extends and super wildcards?","Its signature is `static \u003CT extends Object & Comparable\u003C? super T>> T\nmax(Collection\u003C? extends T> coll)`. The two wildcards do different jobs:\n`Collection\u003C? extends T>` lets it accept any subtype collection (the collection\n**produces** `T`s), and `Comparable\u003C? super T>` lets a type be ordered by a\ncomparator **inherited from an ancestor**.\n\n```java\nclass Animal implements Comparable\u003CAnimal> { \u002F* ... *\u002F }\nclass Dog extends Animal { }\n\nList\u003CDog> dogs = List.of(new Dog(), new Dog());\nDog biggest = Collections.max(dogs); \u002F\u002F Dog uses Animal's Comparable\u003CAnimal>\n```\n\nThe `super` on `Comparable` is the key flexibility: `Dog` doesn't need its own\n`compareTo` — inheriting `Comparable\u003CAnimal>` suffices. This is PECS applied to\nthe comparison itself.\n",{"id":1643,"difficulty":105,"q":1644,"a":1645},"addall-signature","How does Collection.addAll use wildcards?","`boolean addAll(Collection\u003C? extends E> c)` uses an **upper-bounded** wildcard\nbecause the source collection is a **producer** — `addAll` only **reads** from\n`c` and writes into `this`. That lets you add a collection of any subtype of\n`E`.\n\n```java\nList\u003CNumber> nums = new ArrayList\u003C>();\nList\u003CInteger> ints = List.of(1, 2, 3);\nnums.addAll(ints);     \u002F\u002F ok — Integer extends Number (producer)\n```\n\nWithout `? extends E` you could only pass an exact `Collection\u003CE>`, forcing\ncallers to convert. This is the \"Producer Extends\" half of PECS in the standard\nlibrary.\n",{"id":1647,"difficulty":105,"q":1648,"a":1649},"cant-instantiate-wildcard","Can you use a wildcard when creating an object with new?","**No.** You can't write `new` with a wildcard type — the compiler needs a\nconcrete type argument to know what to construct. Wildcards are for **variable,\nparameter, and field types**, not instantiation.\n\n```java\nList\u003C?> ok = new ArrayList\u003CString>();   \u002F\u002F wildcard on the VARIABLE — fine\nList\u003C?> bad = new ArrayList\u003C?>();        \u002F\u002F compile error — can't instantiate \u003C?>\nvar list = new ArrayList\u003C>();            \u002F\u002F diamond infers \u003CObject>, not a wildcard\n```\n\nThe diamond `\u003C>` is **not** a wildcard — it tells the compiler to *infer* a\nconcrete type from context. A genuine `\u003C?>` has no concrete type to allocate, so\nconstruction is forbidden.\n",{"id":1651,"difficulty":105,"q":1652,"a":1653},"wildcards-in-return-types","Why are wildcards discouraged in return types?","A wildcard in a **return type** leaks into the caller's code: they're forced to\ndeal with `\u003C?>` (read-only, capture errors) even though it gave them no\nflexibility. The advice (Effective Java) is to use wildcards on **parameters**,\nnot returns.\n\n```java\n\u002F\u002F bad: caller now holds a List\u003C?> they can barely use\nstatic List\u003C?> bad() { return new ArrayList\u003CString>(); }\n\n\u002F\u002F good: return a concrete or named type\nstatic \u003CT> List\u003CT> good(T seed) { return new ArrayList\u003C>(); }\n```\n\nIf a method's return type would need a wildcard, that's usually a sign it should\ntake a **type parameter** instead, so the caller gets a usable concrete type.\n",{"id":1655,"difficulty":126,"q":1656,"a":1657},"nested-wildcards","How do nested wildcards like List\u003CList\u003C?>> behave?","Wildcards apply at **each level independently**. `List\u003CList\u003C?>>` is a list whose\nelements are each \"a list of some unknown type\" — and crucially that **outer\nlist is invariant**: it is *not* the same as `List\u003CList\u003CString>>`.\n\n```java\nList\u003CList\u003C?>> outer = new ArrayList\u003C>();\nouter.add(List.of(1, 2));        \u002F\u002F ok — inner is List\u003C? = Integer>\nouter.add(List.of(\"a\"));         \u002F\u002F ok — inner is List\u003C? = String>\n\nList\u003CList\u003CString>> strs = new ArrayList\u003C>();\nList\u003CList\u003C?>> alias = strs;      \u002F\u002F compile error — outer level is invariant\n```\n\nTo accept \"a list of lists of anything\" you need `List\u003C? extends List\u003C?>>` on\nthe outer level too. Mixing levels (`List\u003C? extends List\u003C? extends Number>>`) is\nlegal but a readability red flag.\n",{"id":1659,"difficulty":126,"q":1660,"a":1661},"bounded-wildcard-vs-bounded-param-return","Why does a bounded type parameter, not a wildcard, let you return the element type?","A **wildcard has no name**, so you can't mention it in a return type — the best\nyou could return is `Object` or another wildcard. A **type parameter is named**,\nso it can appear in the return position and flow that exact type back to the\ncaller.\n\n```java\n\u002F\u002F wildcard: can't name the element type to return it\nstatic Number first(List\u003C? extends Number> l) { return l.get(0); } \u002F\u002F only Number\n\n\u002F\u002F type parameter: returns the caller's exact T\nstatic \u003CT extends Number> T firstTyped(List\u003CT> l) { return l.get(0); }\nInteger i = firstTyped(List.of(1, 2)); \u002F\u002F gets Integer back, not just Number\n```\n\nSo when the *output* type must match the *input* element type, a named bounded\ntype parameter is required.\n",{"id":1663,"difficulty":126,"q":1664,"a":1665},"comparator-super-wildcard","Why do sort and Comparator parameters use \u003C? super T>?","A `Comparator\u003C? super T>` lets you sort a `List\u003CT>` with a comparator defined\nfor `T` **or any of its supertypes** — the comparator is a **consumer** of `T`s,\nso PECS says `super`. You shouldn't be forced to write a `T`-specific comparator\nwhen an ancestor's already works.\n\n```java\n\u002F\u002F List.sort signature: void sort(Comparator\u003C? super E> c)\nList\u003CDog> dogs = new ArrayList\u003C>(\u002F* ... *\u002F);\nComparator\u003CAnimal> byAge = Comparator.comparingInt(Animal::age);\ndogs.sort(byAge);     \u002F\u002F ok — a Comparator\u003CAnimal> can compare Dogs (super)\n```\n\nWithout `super` you'd have to duplicate `byAge` as a `Comparator\u003CDog>`. This\n\"Consumer Super\" usage is one of the most common real-world wildcard payoffs.\n",{"id":1667,"difficulty":105,"q":1668,"a":1669},"get-put-principle","What is the get-and-put principle and how does it relate to PECS?","The **get-and-put principle** is the same rule as PECS stated mechanically:\nuse `extends` when you only **get** values out, use `super` when you only\n**put** values in, and use an **exact type** (no wildcard) when you need to do\n**both**.\n\n```java\nList\u003C? extends Number> producer = List.of(1, 2);\nNumber n = producer.get(0);   \u002F\u002F get: ok    | put: forbidden\n\nList\u003C? super Integer> consumer = new ArrayList\u003CNumber>();\nconsumer.add(7);              \u002F\u002F put: ok     | get returns only Object\n\nList\u003CInteger> both = new ArrayList\u003C>();\nboth.add(7); int x = both.get(0); \u002F\u002F exact type: get AND put both work\n```\n\nSo if a method must read *and* write the same element type, drop the wildcard\nand use a concrete type or a named type parameter.\n",{"description":103},"Java generics wildcards interview questions — unbounded, upper- and lower-bounded wildcards, the PECS principle, bounded type parameters, multiple bounds, and wildcard capture.","java\u002Fgenerics\u002Fwildcards-bounds","Wildcards & Bounded Types","Q4MMlXMr2OlzLlAypo6k565_DfRC63kkkhC4vyNUgmM",{"id":1676,"title":1677,"body":1678,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":1682,"navigation":108,"order":29,"path":1683,"questions":1684,"questionsCount":1764,"related":250,"seo":1765,"seoDescription":1766,"stem":1767,"subtopic":1677,"topic":81,"topicSlug":83,"updated":809,"__hash__":1768},"qa\u002Fjava\u002Fjvm-internals\u002Fgarbage-collection.md","Garbage Collection",{"type":100,"value":1679,"toc":1680},[],{"title":103,"searchDepth":29,"depth":29,"links":1681},[],{},"\u002Fjava\u002Fjvm-internals\u002Fgarbage-collection",[1685,1689,1693,1697,1701,1705,1709,1713,1717,1721,1725,1728,1732,1736,1740,1744,1748,1752,1756,1760],{"id":1686,"difficulty":113,"q":1687,"a":1688},"what-is-gc","What is garbage collection in Java and why is it needed?","**Garbage collection (GC)** is the automatic process by which the JVM\nidentifies and reclaims heap memory occupied by objects that are no longer\nreachable from any **GC root** (live thread, static field, JNI reference).\nWithout GC, developers would have to `free()` objects manually — the source\nof dangling-pointer and double-free bugs in languages like C.\n\n```java\nvoid createAndForget() {\n    String s = new String(\"temporary\"); \u002F\u002F allocated on heap\n}   \u002F\u002F s goes out of scope → no reference remains → object is unreachable\n    \u002F\u002F GC will reclaim it on the next collection cycle\n```\n\n**Rule of thumb:** GC removes unreachable objects; it does NOT remove\nobjects that are still referenced even if you'll never use them again —\nthat's a memory leak.\n",{"id":1690,"difficulty":105,"q":1691,"a":1692},"mark-and-sweep","How does the mark-and-sweep GC algorithm work?","**Mark-and-sweep** runs in two phases:\n\n1. **Mark** — start from every GC root and trace all reachable objects,\n   setting a \"live\" bit on each one.\n2. **Sweep** — scan the entire heap; reclaim any object without the live\n   bit set; clear live bits for next cycle.\n\n```\nHeap before GC:   [A (live)] [B (dead)] [C (live)] [D (dead)]\nAfter mark:       [A ✓]      [B  ]      [C ✓]      [D  ]\nAfter sweep:      [A]        [free]      [C]         [free]\n```\n\nThe downside is **fragmentation** — freed slots are scattered, making large\nallocations hard. Modern collectors add a **compaction** phase to slide live\nobjects together and reset the allocation pointer.\n\n**Rule of thumb:** mark-and-sweep tells you *what* to collect; compaction\ntells you how to make the freed space *usable*.\n",{"id":1694,"difficulty":105,"q":1695,"a":1696},"generational-gc","Why do modern JVMs use generational garbage collection?","The **weak generational hypothesis** — most objects die young — means that\ncollecting only the small, short-lived Young Generation most of the time is\nfar more efficient than scanning the whole heap every GC cycle.\n\n| GC type | Region swept | Frequency | Typical pause |\n|---|---|---|---|\n| **Minor GC** | Young Gen (Eden + Survivors) | frequent | ms |\n| **Major\u002FFull GC** | Entire heap | infrequent | tens of ms → seconds |\n\n```java\n\u002F\u002F Allocation pattern that plays nicely with generational GC:\nvoid processRequest() {\n    List\u003CItem> results = new ArrayList\u003C>(); \u002F\u002F short-lived; dies in Eden\n    for (Item i : fetch()) results.add(process(i));\n    return results;\n}   \u002F\u002F results unreachable after method returns → collected cheaply\n```\n\n**Rule of thumb:** keep temporary objects truly temporary — objects that\nescape into long-lived caches defeat generational GC and inflate Old Gen.\n",{"id":1698,"difficulty":113,"q":1699,"a":1700},"serial-gc","What is the Serial GC and when is it appropriate?","The **Serial GC** (`-XX:+UseSerialGC`) uses a **single thread** for both\nMinor and Major GC. The entire JVM stops during collection\n(stop-the-world). It is the simplest collector and has the lowest overhead\nper collection, but pauses are longest when the heap is large.\n\n```bash\njava -XX:+UseSerialGC -Xmx256m MyApp\n```\n\nIt is appropriate for:\n- **Small heaps** (\u003C ~256 MB)\n- **Single-core machines** or environments with very few CPUs\n- **Embedded** or **batch** workloads where pause time is not a concern\n\n**Rule of thumb:** Serial GC is correct for tiny, single-threaded CLI\ntools; any latency-sensitive server should use a concurrent collector.\n",{"id":1702,"difficulty":113,"q":1703,"a":1704},"parallel-gc","What is the Parallel GC and how does it differ from Serial?","The **Parallel GC** (also called Throughput Collector, `-XX:+UseParallelGC`,\ndefault before Java 9) uses **multiple threads** for both Minor and Full\nGC, cutting pause times compared to Serial. The application still stops\nduring GC, but the work is divided across cores.\n\n```bash\njava -XX:+UseParallelGC -XX:ParallelGCThreads=8 MyApp\n```\n\nIt maximises **throughput** (fraction of time not spent in GC) at the cost\nof longer individual pauses than concurrent collectors. A good fit for\n**batch jobs** that care more about total work done than per-request latency.\n\n**Rule of thumb:** Parallel GC = maximum throughput, accept the pauses;\nchoose a concurrent collector (G1, ZGC) when latency matters.\n",{"id":1706,"difficulty":105,"q":1707,"a":1708},"cms-gc","What was the CMS GC and why was it removed?","**Concurrent Mark-Sweep (CMS)** (`-XX:+UseConcMarkSweepGC`) ran most of its\nwork **concurrently** with the application, greatly reducing Old Gen pause\ntimes. It had two short stop-the-world phases (initial mark, remark) and\nlong concurrent phases for marking and sweeping.\n\nIts flaws:\n- **No compaction** — memory fragmentation grew over time, eventually\n  causing a \"concurrent mode failure\" that triggered a full stop-the-world\n  compacting collection.\n- High CPU overhead from running GC threads alongside the app.\n- Deprecated in Java 9, **removed in Java 14**.\n\n```bash\n# No longer valid in Java 14+:\n# java -XX:+UseConcMarkSweepGC ...\n```\n\n**Rule of thumb:** CMS is a historical reference; in interviews, position\nG1 as its replacement and ZGC\u002FShenandoah as the next evolution.\n",{"id":1710,"difficulty":105,"q":1711,"a":1712},"g1-gc","How does the G1 garbage collector work?","**G1 (Garbage First)** is the default GC since Java 9. It divides the heap\ninto equal-sized **regions** (1–32 MB each) instead of fixed Eden\u002FSurvivor\u002F\nOld Gen areas. Each region is labelled dynamically.\n\nG1 collects the regions with the most garbage first (hence \"Garbage First\"),\nproviding **predictable pause targets** via `-XX:MaxGCPauseMillis` (default\n200 ms). It runs most work concurrently and compacts incrementally.\n\n```bash\njava -XX:+UseG1GC -XX:MaxGCPauseMillis=100 MyApp\n```\n\nKey G1 concepts:\n- **Humongous regions** — objects > 50 % of region size get their own\n  contiguous region(s); avoid creating many large short-lived objects.\n- **Mixed GC** — after a concurrent marking cycle, G1 collects Young Gen\n  plus the most garbage-dense Old Gen regions together.\n\n**Rule of thumb:** G1 is the right default for most Java apps; tune\n`-XX:MaxGCPauseMillis` first before reaching for exotic flags.\n",{"id":1714,"difficulty":126,"q":1715,"a":1716},"zgc","What makes ZGC different from G1 and when would you choose it?","**ZGC** (`-XX:+UseZGC`, production-ready since Java 15) is designed for\n**sub-millisecond pause times** regardless of heap size (tested up to\nterabytes). It achieves this with three techniques:\n\n1. **Colored pointers** — GC metadata is encoded into the unused upper bits\n   of 64-bit references, eliminating separate per-object GC state.\n2. **Load barriers** — every reference load (not just writes) triggers a\n   barrier that fixes up pointers during concurrent relocation, so the app\n   never stops while objects are moved.\n3. **Concurrent relocation** — objects are moved while the application runs,\n   unlike G1 which stops for evacuation.\n\n```bash\njava -XX:+UseZGC -Xmx16g MyLatencySensitiveApp\n```\n\nChoose ZGC when **tail latency** (p99\u002Fp999) matters more than throughput —\ne.g., real-time APIs, trading systems, or interactive services.\n\n**Rule of thumb:** ZGC trades some throughput for near-zero pause times;\nG1 is simpler and usually sufficient unless you're measuring tail latencies\nbelow 10 ms.\n",{"id":1718,"difficulty":126,"q":1719,"a":1720},"shenandoah","What is Shenandoah GC and how does it compare to ZGC?","**Shenandoah** is a low-pause GC developed by Red Hat, available in\nOpenJDK since Java 12. Like ZGC it relocates objects **concurrently**, but\nuses **Brooks pointers** (an indirection word in the object header) rather\nthan colored pointer bits, making it compatible with 32-bit builds and\ncompressed oops more easily.\n\n```bash\njava -XX:+UseShenandoahGC MyApp\n```\n\n| Aspect | ZGC | Shenandoah |\n|---|---|---|\n| Pause target | \u003C 1 ms | \u003C 10 ms |\n| Concurrent relocation | yes | yes |\n| Mechanism | colored pointers + load barriers | Brooks pointer + barriers |\n| Vendor | Oracle\u002FOpenJDK | Red Hat\u002FOpenJDK |\n\nBoth are good low-pause choices; ZGC has slightly lower pause guarantees\nbut higher CPU overhead from load barriers on every pointer dereference.\n\n**Rule of thumb:** ZGC or Shenandoah for ultra-low latency; the choice\noften comes down to benchmark results in your specific workload.\n",{"id":1722,"difficulty":105,"q":1723,"a":1724},"stop-the-world","What is a stop-the-world pause in GC and why can't it be fully avoided?","A **stop-the-world (STW)** pause is a moment when all application threads\nare suspended so the GC can operate on a consistent snapshot of the heap.\nEven concurrent collectors like G1, ZGC, and Shenandoah need short STW\nphases (initial mark, final remark\u002Frerooting) because GC and application\nthreads cannot safely move objects *and* update every reference atomically\nwithout a brief freeze.\n\n```\nTimeline:\n  [App threads running] → [STW: initial mark ~few ms] → [App + GC concurrent]\n                       → [STW: remark ~few ms] → [App threads running]\n```\n\nThe goal of modern collectors is to make STW pauses **short and\npredictable** rather than eliminating them entirely (which is impossible in\ncurrent JVM designs without hardware transactional memory).\n\n**Rule of thumb:** no JVM GC is truly \"pause-free\"; the question is how\n*long* and *frequent* the pauses are.\n",{"id":885,"difficulty":105,"q":1726,"a":1727},"What are GC roots and why are they the starting point for collection?","**GC roots** are objects that are guaranteed to be live — they are the\nseeds from which the collector traces all reachable objects. Any object not\nreachable from a GC root is dead and eligible for collection.\n\nCommon GC roots:\n- Local variables in active **stack frames**\n- **Static fields** of loaded classes\n- **JNI references** (held by native code)\n- References in **active threads**\n\n```java\nstatic Map\u003CInteger, Object> registry = new HashMap\u003C>();\n\u002F\u002F Anything stored in registry is reachable via a static field (GC root)\n\u002F\u002F and will NEVER be collected while the class is loaded\n```\n\n**Rule of thumb:** a Java memory leak is almost always an object still\nreachable from a GC root that you forgot to remove (e.g., an event listener,\na static cache entry, a ThreadLocal that was never cleared).\n",{"id":1729,"difficulty":105,"q":1730,"a":1731},"finalize","What is finalization in Java and why is it discouraged?","If a class overrides `Object.finalize()`, the GC places unreachable\ninstances of that class on a **finalization queue** instead of immediately\nreclaiming them. A dedicated finalizer thread eventually calls `finalize()`,\nthen the object becomes reclaimable on the *next* GC cycle.\n\nProblems with finalization:\n- **Unpredictable timing** — you don't know when or if `finalize()` will run.\n- **Performance** — objects survive at least two extra GC cycles.\n- **Resurrection** — `finalize()` can store `this` somewhere, making the\n  object live again — a source of hard-to-find bugs.\n- **Deprecated in Java 9, scheduled for removal.**\n\n```java\n\u002F\u002F Preferred alternative: AutoCloseable + try-with-resources\nclass Resource implements AutoCloseable {\n    @Override public void close() { \u002F* release resource deterministically *\u002F }\n}\ntry (Resource r = new Resource()) { r.use(); }\n```\n\n**Rule of thumb:** never rely on `finalize()`; use `AutoCloseable` and\n`try-with-resources` for deterministic resource cleanup.\n",{"id":1733,"difficulty":105,"q":1734,"a":1735},"gc-logs","How do you enable and read GC logs in Java 11+?","Java 9+ uses the **Unified Logging** framework for GC output:\n\n```bash\njava -Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=5,filesize=20m MyApp\n```\n\nA typical G1 Minor GC log line:\n```\n[2.345s][info][gc] GC(3) Pause Young (Normal) (G1 Evacuation Pause) 128M->64M(512M) 12.345ms\n```\n\nKey fields: pause type, heap before → after (heap capacity), pause duration.\n\nUseful selectors:\n- `gc` — one line per GC event\n- `gc*` — verbose, includes region details\n- `gc+heap=debug` — heap breakdown before\u002Fafter\n\n**Rule of thumb:** always enable GC logging in production with rolling\nfiles; you cannot replay GC history if you don't capture it, and it is the\nfirst thing you need when diagnosing a latency incident.\n",{"id":1737,"difficulty":105,"q":1738,"a":1739},"gc-tuning-flags","What are the most important GC tuning flags and what do they control?","| Flag | Effect |\n|---|---|\n| `-XX:+UseG1GC` | Select G1 (default Java 9+) |\n| `-XX:MaxGCPauseMillis=N` | G1 pause target (soft goal, default 200 ms) |\n| `-XX:GCTimeRatio=N` | Ratio of GC time to app time (Parallel GC) |\n| `-XX:NewRatio=N` | Old:Young size ratio (e.g., 2 = 1\u002F3 Young) |\n| `-XX:SurvivorRatio=N` | Eden:Survivor ratio within Young Gen |\n| `-XX:MaxTenuringThreshold=N` | GC cycles before promotion to Old Gen |\n| `-XX:G1HeapRegionSize=N` | G1 region size (1–32 MB, power of 2) |\n| `-XX:G1NewSizePercent` \u002F `-XX:G1MaxNewSizePercent` | Young Gen size range for G1 |\n\n```bash\n# Common production starting point for G1:\njava -XX:+UseG1GC -Xms4g -Xmx4g -XX:MaxGCPauseMillis=100 \\\n     -XX:+HeapDumpOnOutOfMemoryError MyApp\n```\n\n**Rule of thumb:** measure first with GC logs before tuning; changing flags\nwithout data is guesswork.\n",{"id":1741,"difficulty":105,"q":1742,"a":1743},"object-promotion","When and how does an object get promoted from Young Gen to Old Gen?","Each time an object survives a Minor GC it is copied to the other Survivor\nspace and its **age counter** (stored in the mark word, max 15 bits) is\nincremented. When the age reaches `-XX:MaxTenuringThreshold` (default 15),\nthe object is **promoted** to Old Gen on the next Minor GC.\n\nPremature promotion also occurs when:\n- A Survivor space is more than 50 % full during a Minor GC — the JVM\n  lowers the effective threshold dynamically (**adaptive tenuring**).\n- The object is **too large** for Survivor — it bypasses Young Gen entirely\n  and goes straight to Old Gen (or a humongous region in G1).\n\n```java\n\u002F\u002F Anti-pattern: large, long-lived cache that pollutes Old Gen quickly\nstatic Map\u003CString, byte[]> cache = new ConcurrentHashMap\u003C>();\nvoid put(String key) {\n    cache.put(key, new byte[1024 * 1024]); \u002F\u002F immediately humongous in G1\n}\n```\n\n**Rule of thumb:** if Old Gen grows steadily without a leak, your objects\nare living too long — reduce object scope or use a proper cache with eviction.\n",{"id":1745,"difficulty":105,"q":1746,"a":1747},"reference-types-gc","How do soft, weak, and phantom references affect GC behaviour?","Java provides reference wrappers that allow the GC to collect the referent\nunder different urgency levels, enabling memory-sensitive caches:\n\n| Type | GC collects when | Main use |\n|---|---|---|\n| `StrongReference` (normal) | Never while reachable | Everything |\n| `SoftReference\u003CT>` | Before throwing OOM | Memory-sensitive caches |\n| `WeakReference\u003CT>` | Next GC, regardless of memory | Canonicalizing maps |\n| `PhantomReference\u003CT>` | After finalization | GC notification \u002F cleanup |\n\n```java\nCache\u003CK, V> cache = new ConcurrentHashMap\u003C>();\nSoftReference\u003Cbyte[]> ref = new SoftReference\u003C>(new byte[1024 * 1024]);\nbyte[] data = ref.get(); \u002F\u002F null if GC evicted it\n```\n\n`WeakHashMap` uses weak references as keys — entries disappear as soon as\nthe key has no strong referent elsewhere.\n\n**Rule of thumb:** prefer explicit cache eviction (size\u002Ftime bounds) over\n`SoftReference` caches — the GC's eviction timing is unpredictable.\n",{"id":1749,"difficulty":126,"q":1750,"a":1751},"concurrent-mode-failure","What is a concurrent mode failure in G1 and how do you fix it?","A **concurrent mode failure** (also called **evacuation failure** in G1)\noccurs when the GC cannot complete its concurrent collection fast enough —\nOld Gen fills up while the concurrent marking cycle is still running. The\nJVM falls back to a **full stop-the-world collection** to avoid an OOM.\n\nIn G1 this appears in logs as:\n```\n[gc] GC(42) To-space exhausted\n[gc] GC(43) Pause Full (G1 Compaction Pause) 2048M->1200M(2048M) 8432.345ms\n```\n\nCommon causes and fixes:\n| Cause | Fix |\n|---|---|\n| Objects promoted to Old Gen faster than G1 marks them | Increase heap (`-Xmx`) or reduce `-XX:MaxGCPauseMillis` to trigger collection sooner |\n| Too few G1 concurrent threads | Increase `-XX:ConcGCThreads` |\n| App creating humongous objects frequently | Increase `-XX:G1HeapRegionSize` |\n\n**Rule of thumb:** repeated evacuation failures are a sign that the heap or\nGC concurrency settings are undersized for the allocation rate.\n",{"id":1753,"difficulty":105,"q":1754,"a":1755},"throughput-vs-latency","How do you choose between a throughput-oriented and a latency-oriented GC?","**Throughput** = fraction of CPU time spent executing application code\n(not GC). Measured over long windows (minutes); long individual pauses are\nacceptable.\n\n**Latency** = individual GC pause duration. Matters for interactive apps,\nAPIs with SLAs, or real-time systems where a 500 ms pause is unacceptable.\n\n| GC | Optimises | Best for |\n|---|---|---|\n| Parallel GC | Throughput | Batch jobs, offline processing |\n| G1 | Balanced (default 200 ms goal) | General-purpose servers |\n| ZGC \u002F Shenandoah | Latency (\u003C 1–10 ms) | Low-latency APIs, trading, streaming |\n\n```bash\n# Batch job: maximise throughput\njava -XX:+UseParallelGC -XX:GCTimeRatio=19 BatchJob   # 95 % app, 5 % GC\n\n# API server: limit pause time\njava -XX:+UseG1GC -XX:MaxGCPauseMillis=50 ApiServer\n```\n\n**Rule of thumb:** measure your SLA requirements first — if p99 latency\nalready meets the SLA with G1, there is no reason to switch to ZGC.\n",{"id":1757,"difficulty":105,"q":1758,"a":1759},"system-gc","What does System.gc() do and why should you avoid it?","`System.gc()` is a **hint** to the JVM to run a full GC. The JVM may ignore\nit (especially with `-XX:+DisableExplicitGC`, which is common in production).\nWhen it is honoured it triggers a **Full GC** — the most expensive GC event.\n\n```java\nSystem.gc(); \u002F\u002F hint — may trigger Full GC, may be ignored\n```\n\nWhy to avoid it:\n- Forces an expensive Full GC at an unpredictable point, causing a long\n  pause that can violate SLAs.\n- The GC is better at deciding *when* to collect than application code.\n- Commonly a sign of premature optimisation or misunderstanding of GC.\n\nLegitimate use: in benchmarking code, called before each measurement to\nstart from a clean heap. Even then, use `Runtime.getRuntime().gc()` in a\nloop and confirm GC actually ran with logs.\n\n**Rule of thumb:** never call `System.gc()` in production code; remove it\nimmediately if you find it in a code review.\n",{"id":1761,"difficulty":126,"q":1762,"a":1763},"gc-safe-points","What is a safepoint in the JVM and how does it relate to GC?","A **safepoint** is a point in the execution of application threads at which\nthe JVM can safely inspect or modify the heap — all threads are at a\nconsistent, known state (no partially-constructed objects being referenced).\nBefore a stop-the-world GC phase, the JVM requests all threads to reach\ntheir next safepoint and halt.\n\nSafepoint checks are inserted by the JIT at method returns, backward\nbranches (loop backs), and certain other locations. A thread that is\nexecuting a long counted loop without a backward branch may delay GC by\nfailing to reach a safepoint quickly — the \"safepoint bias\" problem,\nmitigated in Java 10+ with `-XX:+UseCountedLoopSafepoints`.\n\n```\n\u002F\u002F A tight counted loop may delay safepoint:\nfor (int i = 0; i \u003C 1_000_000_000; i++) {\n    sum += array[i]; \u002F\u002F no backward branch safepoint in old JVMs\n}\n```\n\n**Rule of thumb:** if GC pause logs show suspiciously long \"time to\nsafepoint\" entries, look for long-running counted loops in the hot path.\n",20,{"description":103},"Java garbage collection interview questions — GC algorithms, Serial\u002FParallel\u002FG1\u002FZGC\u002FShenandoah collectors, stop-the-world pauses, Minor vs Full GC, GC tuning flags, GC logs, finalization, and avoiding common GC anti-patterns.","java\u002Fjvm-internals\u002Fgarbage-collection","2johcH0Z2_nzkPh5ipjG3e4H_tf9-Huj2tNCW4bfxxQ",{"id":1770,"title":1771,"body":1772,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":1776,"navigation":108,"order":29,"path":1777,"questions":1778,"questionsCount":1835,"related":250,"seo":1836,"seoDescription":1837,"stem":1838,"subtopic":1771,"topic":90,"topicSlug":92,"updated":809,"__hash__":1839},"qa\u002Fjava\u002Fmodern-java\u002Fsealed-classes.md","Sealed Classes",{"type":100,"value":1773,"toc":1774},[],{"title":103,"searchDepth":29,"depth":29,"links":1775},[],{},"\u002Fjava\u002Fmodern-java\u002Fsealed-classes",[1779,1783,1787,1791,1795,1799,1803,1807,1811,1815,1819,1823,1827,1831],{"id":1780,"difficulty":113,"q":1781,"a":1782},"what-are-sealed-classes","What are sealed classes in Java and what problem do they solve?","**Sealed classes** (Java 17, JEP 409) restrict which classes or interfaces\nmay **directly extend or implement** them using a `permits` clause. They\nsolve the problem of open inheritance hierarchies where any unknown class\ncan subclass your type, preventing exhaustive analysis by the compiler or\nby pattern-matching switches.\n\n```java\npublic sealed interface Shape permits Circle, Rectangle, Triangle {}\n```\n\nNow only `Circle`, `Rectangle`, and `Triangle` can implement `Shape`.\nAny other class attempting `implements Shape` is a **compile error**.\n\n**Rule of thumb:** use sealed classes when you own the full set of\nsubtypes and want the compiler to enforce exhaustive handling.\n",{"id":1784,"difficulty":113,"q":1785,"a":1786},"permits-clause","What is the permits clause and when can it be omitted?","The `permits` clause lists every allowed direct subtype. If all permitted\nsubtypes are in the **same source file** as the sealed class, the `permits`\nclause may be **omitted** and the compiler infers it from the file:\n\n```java\n\u002F\u002F Explicit permits — subtypes may be in separate files:\npublic sealed class Expr permits Num, Add, Mul {}\n\n\u002F\u002F Implicit permits — all in one file:\nsealed class Result\u003CT> {\n    record Ok\u003CT>(T value)    extends Result\u003CT> {}\n    record Err(String msg)   extends Result\u003CVoid> {}\n}\n```\n\nWhen subtypes are in **different packages or modules**, the `permits`\nclause is mandatory and the subtypes must be in the same package (for\nnon-modular code) or accessible module.\n\n**Rule of thumb:** omit `permits` for concise single-file hierarchies;\nuse explicit `permits` when subtypes live in separate files.\n",{"id":1788,"difficulty":105,"q":1789,"a":1790},"permitted-subtype-modifiers","What modifiers must a permitted subtype carry?","Every direct subtype of a sealed class\u002Finterface must be marked with\nexactly one of three modifiers:\n\n| Modifier | Meaning |\n|---|---|\n| `final` | Cannot be extended further — closes the hierarchy |\n| `sealed` | Can be extended, but only by its own `permits` list |\n| `non-sealed` | Opens the hierarchy again — anyone can extend this subtype |\n\n```java\nsealed interface Notification permits Email, Push, Sms {}\n\nfinal class Email implements Notification {}    \u002F\u002F no further subclasses\n\nsealed class Push implements Notification       \u002F\u002F further restricted\n    permits AndroidPush, IosPush {}\nfinal class AndroidPush extends Push {}\nfinal class IosPush     extends Push {}\n\nnon-sealed class Sms implements Notification {} \u002F\u002F open again — anyone can extend\nclass SmsPremium extends Sms {}                 \u002F\u002F allowed\n```\n\n**Rule of thumb:** use `final` for leaf types, `sealed` for multi-level\nhierarchies, and `non-sealed` sparingly when you intentionally want to\nre-open extensibility.\n",{"id":1792,"difficulty":105,"q":1793,"a":1794},"sealed-vs-abstract","What is the difference between a sealed class and an abstract class?","An **abstract class** restricts *instantiation* — you can't call `new`\non it — but it places **no restriction on subclassing**; anyone can extend\nit. A **sealed class** restricts *who can subclass it* — only the `permits`\nlist — but a sealed class can itself be concrete or abstract.\n\n| Aspect | abstract class | sealed class |\n|---|---|---|\n| Prevents instantiation | Yes | Only if also `abstract` |\n| Restricts subclassing | No — anyone can extend | Yes — only `permits` list |\n| Compiler exhaustiveness | No | Yes (with switch pattern matching) |\n\n```java\nabstract sealed class Vehicle permits Car, Truck {}\n\u002F\u002F abstract → can't do new Vehicle()\n\u002F\u002F sealed   → only Car and Truck can extend Vehicle\n```\n\n**Rule of thumb:** combine `abstract sealed` when you want both — no direct\ninstances AND a closed subtype set.\n",{"id":1796,"difficulty":113,"q":1797,"a":1798},"sealed-interfaces","Can interfaces be sealed?","Yes. Sealed interfaces work identically to sealed classes but with\n`implements` instead of `extends`. They are particularly useful with\n**records**, since records are implicitly `final` and naturally close the\nhierarchy:\n\n```java\nsealed interface JsonValue\n    permits JsonString, JsonNumber, JsonBool, JsonNull, JsonArray, JsonObject {}\n\nrecord JsonString(String value) implements JsonValue {}\nrecord JsonNumber(double value) implements JsonValue {}\nrecord JsonBool(boolean value)  implements JsonValue {}\nrecord JsonNull()               implements JsonValue {}\n\u002F\u002F JsonArray and JsonObject might be non-record classes\n```\n\n**Rule of thumb:** sealed interfaces + records are the idiomatic way to\nmodel **algebraic data types (ADTs)** in Java — think Rust enums or\nHaskell sum types.\n",{"id":1800,"difficulty":105,"q":1801,"a":1802},"exhaustive-switch","How do sealed classes enable exhaustive switch expressions?","Because the compiler knows the complete set of subtypes of a sealed type,\na `switch` expression over that type can be verified as **exhaustive**\nat compile time — no default case needed:\n\n```java\nsealed interface Shape permits Circle, Square {}\nrecord Circle(double r) implements Shape {}\nrecord Square(double side) implements Shape {}\n\ndouble area(Shape s) {\n    return switch (s) {              \u002F\u002F exhaustive — compiler knows all cases\n        case Circle c  -> Math.PI * c.r() * c.r();\n        case Square sq -> sq.side() * sq.side();\n    };\n    \u002F\u002F No default needed; adding a new Shape subtype would cause a compile error here\n}\n```\n\nIf you add a new permitted subtype later, every exhaustive switch that\ndoesn't handle it becomes a **compile error** — the compiler guides you\nto all the places that need updating.\n\n**Rule of thumb:** exhaustive switch over a sealed type is the Java\nreplacement for the visitor pattern — compile-time safety instead of\nruntime dispatch tables.\n",{"id":1804,"difficulty":105,"q":1805,"a":1806},"sealed-and-pattern-matching","How do sealed classes combine with pattern matching?","Pattern matching in `switch` (Java 21) gains the most power when used\nwith sealed types because the compiler can check exhaustiveness. You can\nalso **deconstruct record components** inline:\n\n```java\nsealed interface Expr permits Num, Add {}\nrecord Num(int value)       implements Expr {}\nrecord Add(Expr l, Expr r)  implements Expr {}\n\nint eval(Expr e) {\n    return switch (e) {\n        case Num(int v)         -> v;\n        case Add(Expr l, Expr r) -> eval(l) + eval(r);\n    };\n}\n\nSystem.out.println(eval(new Add(new Num(1), new Num(2)))); \u002F\u002F 3\n```\n\n**Rule of thumb:** sealed + records + switch pattern matching together\nmodel recursive data structures (ASTs, JSON trees, result types) cleanly\nand safely.\n",{"id":1808,"difficulty":105,"q":1809,"a":1810},"sealed-vs-enum","When would you use a sealed class instead of an enum?","**Enums** are fixed singletons — each constant is a single shared instance\nwith no per-instance state beyond what's in enum fields. **Sealed classes**\nallow each subtype to carry **different data** and have distinct structure.\n\n| | Enum | Sealed class |\n|---|---|---|\n| Per-instance data | Same fields for all constants | Each subtype can have different fields |\n| Extensibility | Closed (compile time) | Closed (compile time) |\n| Exhaustive switch | Yes | Yes (Java 21) |\n| Polymorphic behaviour | Via abstract methods | Via subtype methods |\n\n```java\n\u002F\u002F Enum: same structure, different values\nenum Status { PENDING, ACTIVE, CLOSED }\n\n\u002F\u002F Sealed: different structure per variant\nsealed interface Event permits OrderPlaced, OrderShipped, OrderCancelled {}\nrecord OrderPlaced(String orderId, Instant at)         implements Event {}\nrecord OrderShipped(String orderId, String carrier)    implements Event {}\nrecord OrderCancelled(String orderId, String reason)   implements Event {}\n```\n\n**Rule of thumb:** use enum when all variants are structurally identical;\nuse sealed class when variants carry different data.\n",{"id":1812,"difficulty":126,"q":1813,"a":1814},"sealed-with-generics","Can sealed classes be generic?","Yes. Sealed classes and interfaces can be generic, and permitted subtypes\nmay fix or forward the type parameters:\n\n```java\nsealed interface Either\u003CL, R> permits Either.Left, Either.Right {\n    record Left\u003CL, R>(L value)  implements Either\u003CL, R> {}\n    record Right\u003CL, R>(R value) implements Either\u003CL, R> {}\n}\n\nEither\u003CString, Integer> result = new Either.Left\u003C>(\"error\");\n\nString msg = switch (result) {\n    case Either.Left\u003CString, Integer>(String s)  -> \"Error: \" + s;\n    case Either.Right\u003CString, Integer>(Integer n) -> \"Value: \" + n;\n};\n```\n\n**Rule of thumb:** generic sealed types model functional algebraic\ntypes like `Either`, `Option`, or `Result` natively in Java without\nthird-party libraries.\n",{"id":1816,"difficulty":126,"q":1817,"a":1818},"sealed-and-reflection","How can you inspect a sealed class's permitted subtypes at runtime?","Java 17 added `Class.permittedSubclasses()` which returns an array of\n`ClassDesc` descriptors (or use `Class.getPermittedSubclasses()` which\nreturns `Class\u003C?>[]` in preview; in standard API it returns\n`ClassDesc[]`). In practice most code uses the standard method:\n\n```java\nsealed interface Shape permits Circle, Square {}\nfinal record Circle(double r) implements Shape {}\nfinal record Square(double s) implements Shape {}\n\nClass\u003C?>[] permitted = Shape.class.getPermittedSubclasses();\nfor (Class\u003C?> c : permitted) {\n    System.out.println(c.getName());\n    \u002F\u002F prints: Circle, Square\n}\n```\n\nThis allows frameworks (serialisation libraries, UI generators) to\ndiscover the full closed set of subtypes at runtime without classpath\nscanning.\n\n**Rule of thumb:** `getPermittedSubclasses()` gives you the closed type\nset at runtime — use it in frameworks to drive deserialization or\nschema generation without annotation scanning.\n",{"id":1820,"difficulty":105,"q":1821,"a":1822},"sealed-modelling-result","How would you model a Result type (success or failure) using sealed classes?","Sealed classes are the idiomatic way to represent **sum types** like\n`Result\u003CT>` — a value that is either a success carrying a result or a\nfailure carrying an error:\n\n```java\nsealed interface Result\u003CT> permits Result.Ok, Result.Err {\n    record Ok\u003CT>(T value)      implements Result\u003CT> {}\n    record Err\u003CT>(String msg)  implements Result\u003CT> {}\n}\n\nResult\u003CInteger> parse(String s) {\n    try { return new Result.Ok\u003C>(Integer.parseInt(s)); }\n    catch (NumberFormatException e) { return new Result.Err\u003C>(e.getMessage()); }\n}\n\n\u002F\u002F Pattern-match at call site:\nswitch (parse(\"42\")) {\n    case Result.Ok\u003CInteger>(int v)  -> System.out.println(\"Parsed: \" + v);\n    case Result.Err\u003CInteger>(String m) -> System.err.println(\"Failed: \" + m);\n}\n```\n\n**Rule of thumb:** a sealed `Result` type makes error paths visible in\nthe type system — callers *must* handle both cases, unlike checked\nexceptions which are often swallowed.\n",{"id":1824,"difficulty":105,"q":1825,"a":1826},"non-sealed-purpose","Why would you mark a permitted subtype as non-sealed?","`non-sealed` intentionally **re-opens** the hierarchy below a sealed\ntype. You'd use it when you own the sealed root (for exhaustive internal\ndispatch) but want to allow third-party code to extend a specific branch:\n\n```java\nsealed interface Plugin permits CorePlugin, ExtensionPlugin {}\nfinal class CorePlugin    implements Plugin {}   \u002F\u002F internal, closed\nnon-sealed class ExtensionPlugin implements Plugin {} \u002F\u002F open to third parties\n\nclass MyCustomPlugin extends ExtensionPlugin {}  \u002F\u002F allowed\n```\n\nThe sealed root still gives you a closed set for internal `switch`\nexpressions that only need to distinguish `CorePlugin` vs\n`ExtensionPlugin` (not their subtypes).\n\n**Rule of thumb:** use `non-sealed` to create a deliberate extension\npoint in an otherwise closed hierarchy — document it clearly as a\npublic API contract.\n",{"id":1828,"difficulty":113,"q":1829,"a":1830},"sealed-compile-error-example","What compile errors do sealed classes prevent?","Any class not listed in the `permits` clause that tries to extend or\nimplement the sealed type gets a **compile error**:\n\n```java\nsealed interface Animal permits Dog, Cat {}\nfinal class Dog implements Animal {}\nfinal class Cat implements Animal {}\n\n\u002F\u002F This causes a compile error:\n\u002F\u002F class Fish implements Animal {}\n\u002F\u002F error: Fish is not allowed in the sealed hierarchy\n\n\u002F\u002F This also fails — permitted subtypes must have final\u002Fsealed\u002Fnon-sealed:\n\u002F\u002F class Dog implements Animal {}   \u002F\u002F error: missing modifier\n```\n\nThe compiler also **warns on exhaustive switch** if a new subtype is\nadded to the `permits` list but not handled in existing switches.\n\n**Rule of thumb:** sealed classes turn runtime `ClassCastException` or\nmissed-case bugs into **compile errors** — fix them at build time, not\nin production.\n",{"id":1832,"difficulty":105,"q":1833,"a":1834},"sealed-jdk-examples","Does the JDK itself use sealed classes?","Yes. Several JDK APIs introduced in Java 17–21 use sealed types:\n\n- **`java.lang.constant.ConstantDesc`** — sealed interface with\n  `ClassDesc`, `MethodTypeDesc`, `DynamicConstantDesc`, etc.\n- **`jdk.incubator.vector`** — sealed `VectorShape` hierarchy.\n- Pattern matching in the `switch` expression itself — the language\n  spec describes case selectors using a sealed hierarchy of pattern kinds.\n\n```java\n\u002F\u002F ConstantDesc is sealed — you can exhaustively switch over it:\nConstantDesc desc = ...;\nswitch (desc) {\n    case ClassDesc cd       -> ...;\n    case MethodTypeDesc md  -> ...;\n    \u002F\u002F etc.\n}\n```\n\n**Rule of thumb:** look at `java.lang.constant` for a production-quality\nexample of sealed interfaces in the JDK itself.\n",14,{"description":103},"Java sealed classes interview questions — permits clause, sealed vs abstract, permitted subtypes (final\u002Fsealed\u002Fnon-sealed), sealed interfaces, exhaustive switch, algebraic data types, and sealed classes with records.","java\u002Fmodern-java\u002Fsealed-classes","9QpfaTliEY2U89RE3zmAYqNt6DxbvRpm8_UelBaYDP4",{"id":1841,"title":1842,"body":1843,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":1847,"navigation":108,"order":29,"path":1848,"questions":1849,"questionsCount":1914,"related":250,"seo":1915,"seoDescription":1916,"stem":1917,"subtopic":1842,"topic":28,"topicSlug":30,"updated":1068,"__hash__":1918},"qa\u002Fjava\u002Foop\u002Finheritance.md","Inheritance",{"type":100,"value":1844,"toc":1845},[],{"title":103,"searchDepth":29,"depth":29,"links":1846},[],{},"\u002Fjava\u002Foop\u002Finheritance",[1850,1854,1858,1862,1866,1870,1874,1878,1882,1886,1890,1894,1898,1902,1906,1910],{"id":1851,"difficulty":113,"q":1852,"a":1853},"four-pillars","What are the four pillars of object-oriented programming?","- **Encapsulation** — bundle data with the methods that operate on it and hide\n  internal state behind a public API (private fields + getters\u002Fsetters).\n- **Abstraction** — expose *what* an object does, hide *how*, via interfaces\n  and abstract classes.\n- **Inheritance** — a subclass reuses and extends a superclass's members\n  (`extends`).\n- **Polymorphism** — one reference type, many runtime forms; the actual\n  object's overridden method is called.\n\n```java\nclass Animal { String sound() { return \"...\"; } }\nclass Dog extends Animal { String sound() { return \"Woof\"; } } \u002F\u002F inheritance + override\nAnimal a = new Dog();   \u002F\u002F polymorphism\na.sound();              \u002F\u002F \"Woof\"\n```\n\nA good one-liner: encapsulation hides data, abstraction hides complexity,\ninheritance reuses behavior, polymorphism varies it.\n",{"id":1855,"difficulty":113,"q":1856,"a":1857},"inheritance","What is inheritance and what does Java not allow?","Inheritance lets a subclass acquire the fields and methods of a superclass with\n`extends`, modeling an **is-a** relationship and enabling reuse + polymorphism.\n\n```java\nclass Vehicle { void start() { } }\nclass Car extends Vehicle { void honk() { } } \u002F\u002F Car is-a Vehicle\n```\n\nJava allows **single inheritance** of classes only — a class can extend exactly\none superclass (to avoid the \"diamond problem\"). It *can* implement **multiple\ninterfaces**, which is how Java gets multiple-type flexibility without\nmultiple class inheritance. `final` classes can't be extended at all.\n",{"id":1859,"difficulty":113,"q":1860,"a":1861},"object-superclass","What is the Object class and what does every class inherit from it?","`java.lang.Object` is the **root** of every class hierarchy — if you don't\n`extends` anything, you implicitly extend `Object`. So every object has its\nmethods, the most important being:\n\n- `equals(Object)` \u002F `hashCode()` — value equality and hashing.\n- `toString()` — string representation.\n- `getClass()` — the runtime class.\n- `clone()`, `finalize()` (deprecated), and the `wait`\u002F`notify` family for\n  threading.\n\n```java\nclass Foo { }            \u002F\u002F implicitly: class Foo extends Object\nObject o = new Foo();\no.toString();            \u002F\u002F \"Foo@1b6d3586\" by default\n```\n\n**Rule of thumb:** because everything is-an `Object`, an `Object` reference (or\n`Object[]`) can hold anything — the basis of pre-generics collections.\n",{"id":1863,"difficulty":113,"q":1864,"a":1865},"types-of-inheritance","What types of inheritance does Java support?","- **Single** — one subclass, one superclass. ✅\n- **Multilevel** — a chain (`C extends B extends A`). ✅\n- **Hierarchical** — many subclasses of one parent. ✅\n- **Multiple inheritance of *classes*** — extending two classes. ❌ (not allowed)\n- **Multiple inheritance of *types*** — implementing many interfaces. ✅\n\n```java\nclass A { }\nclass B extends A { }            \u002F\u002F single\nclass C extends B { }            \u002F\u002F multilevel\nclass D extends A { }            \u002F\u002F hierarchical (with B)\nclass E implements I1, I2 { }    \u002F\u002F multiple interfaces — OK\n```\n\n**Rule of thumb:** Java forbids multiple *class* inheritance but allows multiple\n*interface* inheritance — you get many capabilities, but a single implementation\nlineage.\n",{"id":1867,"difficulty":105,"q":1868,"a":1869},"why-no-multiple-inheritance","Why doesn't Java support multiple inheritance of classes?","To avoid the **diamond problem**: if `B` and `C` both extended `A` and overrode\na method, and `D` extended both `B` and `C`, the compiler couldn't tell **which\nversion** `D` inherits. C++ allows it and pays for it with complexity (virtual\ninheritance).\n\n```java\n\u002F\u002F Hypothetical — illegal in Java:\n\u002F\u002F class D extends B, C { }   \u002F\u002F which greet() does D get?\ninterface B { default String greet() { return \"B\"; } }\ninterface C { default String greet() { return \"C\"; } }\nclass D implements B, C {\n  public String greet() { return B.super.greet(); } \u002F\u002F YOU resolve it\n}\n```\n\nJava permits multiple *interface* inheritance because conflicting `default`\nmethods **force the class to resolve the ambiguity explicitly**. **Rule of\nthumb:** Java trades raw power for predictability.\n",{"id":1871,"difficulty":105,"q":1872,"a":1873},"super-keyword","What does the super keyword do?","`super` refers to the **immediate superclass**. It does two jobs: call the\nparent **constructor** (`super(args)`, must be the first statement) and call an\n**overridden** parent method or access a parent field (`super.method()`).\n\n```java\nclass Animal {\n  Animal(String name) { }\n  void describe() { System.out.println(\"an animal\"); }\n}\nclass Dog extends Animal {\n  Dog(String name) {\n    super(name);              \u002F\u002F chain to parent constructor\n  }\n  @Override void describe() {\n    super.describe();         \u002F\u002F reuse parent behavior\n    System.out.println(\"...specifically a dog\");\n  }\n}\n```\n\nIf you don't call `super(...)` explicitly, the compiler inserts a no-arg\n`super()` — which fails to compile if the parent has no no-arg constructor.\n",{"id":1875,"difficulty":105,"q":1876,"a":1877},"constructor-not-inherited","Are constructors inherited? How are they involved in inheritance?","**No** — constructors are not inherited. But every subclass constructor **must**\ninvoke a superclass constructor first, via an explicit `super(...)` or an\nimplicit no-arg `super()` the compiler inserts.\n\n```java\nclass Base {\n  Base(int id) { }            \u002F\u002F no no-arg constructor\n}\nclass Sub extends Base {\n  Sub() { super(1); }         \u002F\u002F MUST call super(int) explicitly\n  \u002F\u002F Sub() { }                \u002F\u002F would NOT compile — implicit super() missing\n}\n```\n\nSo if a parent defines only parameterized constructors, the child is **forced**\nto call one. **Rule of thumb:** inheritance reuses *methods and fields*, not\nconstructors — the child builds the parent's slice of itself by chaining up.\n",{"id":1879,"difficulty":105,"q":1880,"a":1881},"upcasting-downcasting","What is the difference between upcasting and downcasting?","- **Upcasting** — treating a subclass object as its superclass type. Always\n  safe, implicit. Enables polymorphism.\n- **Downcasting** — casting a superclass reference back to a subclass. Needs an\n  **explicit cast** and can throw `ClassCastException` if the object isn't\n  actually that subtype — guard it with `instanceof`.\n\n```java\nAnimal a = new Dog();          \u002F\u002F upcast — implicit, safe\nDog d = (Dog) a;               \u002F\u002F downcast — explicit\nif (a instanceof Cat c) {      \u002F\u002F pattern: test before casting\n  c.meow();\n}\n```\n\n**Rule of thumb:** upcast freely to program to the supertype; downcast rarely,\nand only after an `instanceof` check.\n",{"id":1883,"difficulty":113,"q":1884,"a":1885},"instanceof","What does the instanceof operator do?","`instanceof` tests whether an object is an instance of a given type (or subtype),\nreturning a `boolean`. Since Java 16, **pattern matching** lets you bind a\nvariable in the same expression, avoiding a separate cast.\n\n```java\nObject o = \"hello\";\nif (o instanceof String) { }            \u002F\u002F classic\nif (o instanceof String s) {            \u002F\u002F pattern matching\n  System.out.println(s.length());       \u002F\u002F s is already a String\n}\n```\n\n`null instanceof X` is always `false`. **Rule of thumb:** heavy `instanceof`\nchains are often a smell — prefer polymorphism (let each type implement the\nmethod) unless you're at a true type boundary (deserialization, `equals`).\n",{"id":1887,"difficulty":126,"q":1888,"a":1889},"inheritance-vs-composition","When should you favor composition over inheritance?","**Inheritance** (is-a) tightly couples a subclass to its parent's\nimplementation; changes to the base can silently break subclasses (the \"fragile\nbase class\" problem). **Composition** (has-a) builds behavior by *holding*\nother objects and delegating — looser coupling, more flexible.\n\n```java\n\u002F\u002F inheritance misused: a Stack is-a List? leaks all List methods\nclass Stack\u003CT> extends ArrayList\u003CT> { }\n\n\u002F\u002F composition: Stack HAS a list, exposes only stack operations\nclass Stack\u003CT> {\n  private final List\u003CT> items = new ArrayList\u003C>();\n  void push(T t) { items.add(t); }\n  T pop() { return items.remove(items.size() - 1); }\n}\n```\n\nGuideline (\"favor composition over inheritance\"): use inheritance only for a\ntrue is-a with a stable base designed for extension; otherwise compose. It also\nsidesteps single-inheritance limits.\n",{"id":1891,"difficulty":113,"q":1892,"a":1893},"ducktyping-isa-hasa","What is the difference between an is-a and a has-a relationship?","- **is-a** -> inheritance. A `Car` *is a* `Vehicle` -> `class Car extends\n  Vehicle`.\n- **has-a** -> composition\u002Faggregation. A `Car` *has an* `Engine` -> the `Car`\n  holds an `Engine` field.\n\n```java\nclass Engine { }\nclass Car extends Vehicle {   \u002F\u002F is-a Vehicle\n  private final Engine engine = new Engine(); \u002F\u002F has-a Engine\n}\n```\n\nModeling tip: if you can't truthfully say \"X is a Y,\" don't use inheritance —\nreach for has-a (composition) instead. Misusing is-a (e.g. `Stack extends\nVector`) is a classic design smell.\n",{"id":1895,"difficulty":105,"q":1896,"a":1897},"aggregation-vs-composition","What is the difference between aggregation and composition?","Both are **has-a**, differing in **lifecycle ownership**:\n\n- **Composition** — the part *can't exist* without the whole; the whole owns and\n  creates it (a `House` and its `Room`s). Strong ownership.\n- **Aggregation** — the part can exist independently and may be shared (a `Team`\n  and its `Player`s; players outlive the team).\n\n```java\nclass House {\n  private final Room room = new Room();   \u002F\u002F composition: created\u002Fowned here\n}\nclass Team {\n  private final List\u003CPlayer> players;      \u002F\u002F aggregation: passed in, shared\n  Team(List\u003CPlayer> players) { this.players = players; }\n}\n```\n\n**Rule of thumb:** \"owns and destroys together\" = composition; \"references but\ndoesn't own\" = aggregation.\n",{"id":1899,"difficulty":105,"q":1900,"a":1901},"prevent-inheritance","How do you prevent a class from being subclassed?","Three ways, by strength:\n\n- **`final` class** — outright bans `extends` (e.g. `String`).\n- **`private`\u002Fpackage-private constructors** — no outside subclass can call\n  `super(...)`, so it can't be extended elsewhere.\n- **`sealed` class** (Java 17+) — allows only a named `permits` list of\n  subclasses.\n\n```java\nfinal class Money { }                          \u002F\u002F no subclasses at all\nsealed class Shape permits Circle, Square { }  \u002F\u002F only these two\n```\n\nReasons: protect invariants (an immutable class shouldn't be subclassed into\nmutability), security, and clearer design. **Rule of thumb:** design for\ninheritance *and document it*, or prohibit it with `final`\u002F`sealed`.\n",{"id":1903,"difficulty":105,"q":1904,"a":1905},"cohesion-coupling","What are cohesion and coupling?","- **Cohesion** — how focused a class is on a single responsibility. **High\n  cohesion is good**: a `UserValidator` that only validates users.\n- **Coupling** — how dependent classes are on each other's internals. **Low\n  coupling is good**: classes interact through small, stable interfaces.\n\n```java\n\u002F\u002F low coupling: depends on an interface, not a concrete logger\nclass OrderService {\n  private final Logger log;            \u002F\u002F injected abstraction\n  OrderService(Logger log) { this.log = log; }\n}\n```\n\nThe goal of good OO design is **high cohesion, low coupling** — classes that do\none thing well and lean on each other as little as possible, which makes systems\neasier to change and test.\n",{"id":1907,"difficulty":126,"q":1908,"a":1909},"liskov","What is the Liskov Substitution Principle?","The **L** in SOLID: a subtype must be usable **anywhere its supertype is\nexpected**, without breaking the program's correctness. A subclass that\nstrengthens preconditions, weakens postconditions, or throws on inherited\noperations violates it.\n\n```java\n\u002F\u002F Classic violation: Square is-a Rectangle?\nclass Rectangle { void setWidth(int w){} void setHeight(int h){} }\nclass Square extends Rectangle {\n  void setWidth(int w){ \u002F* also sets height — breaks setWidth's contract *\u002F }\n}\n\u002F\u002F code that sets width then expects height unchanged now fails\n```\n\nThe fix is usually composition or a shared abstraction, not inheritance. **Rule\nof thumb:** if a subclass can't honor everything the parent promises, it\nshouldn't extend it.\n",{"id":1911,"difficulty":126,"q":1912,"a":1913},"solid","What do the SOLID principles stand for?","Five OO design principles for maintainable code:\n\n- **S** — Single Responsibility: a class has one reason to change.\n- **O** — Open\u002FClosed: open for extension, closed for modification.\n- **L** — Liskov Substitution: subtypes must be usable wherever their base is.\n- **I** — Interface Segregation: prefer small, specific interfaces over fat ones.\n- **D** — Dependency Inversion: depend on abstractions, not concretions.\n\n```java\n\u002F\u002F Dependency Inversion: high-level code depends on an interface\ninterface Repository { void save(Order o); }\nclass OrderService {\n  private final Repository repo;       \u002F\u002F not a concrete DB class\n  OrderService(Repository repo) { this.repo = repo; }\n}\n```\n\nLiskov is the one interviewers probe most: a subclass that throws on, or\nweakens, an inherited method (the `Square extends Rectangle` problem) violates\nit.\n",16,{"description":103},"Java inheritance interview questions — extends and super, single vs multiple inheritance, the Object superclass, is-a vs has-a, composition over inheritance, upcasting and downcasting, Liskov substitution and SOLID.","java\u002Foop\u002Finheritance","5xZiWFIeS1BBeBN1394_sjmozGSS0qp9FdmN-_BRl9o",{"id":1920,"title":1921,"body":1922,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":1926,"navigation":108,"order":29,"path":1927,"questions":1928,"questionsCount":904,"related":250,"seo":2013,"seoDescription":2014,"stem":2015,"subtopic":2016,"topic":55,"topicSlug":56,"updated":809,"__hash__":2017},"qa\u002Fjava\u002Fstreams-functional\u002Fstreams-api.md","Streams Api",{"type":100,"value":1923,"toc":1924},[],{"title":103,"searchDepth":29,"depth":29,"links":1925},[],{},"\u002Fjava\u002Fstreams-functional\u002Fstreams-api",[1929,1933,1937,1941,1945,1949,1953,1957,1961,1965,1969,1973,1977,1981,1985,1989,1993,1997,2001,2005,2009],{"id":1930,"difficulty":113,"q":1931,"a":1932},"what-is-a-stream","What is a Stream in Java and how does it differ from a collection?","A **`Stream`** is not a data structure — it's a **pipeline** that carries\nelements from a **source** (a collection, array, generator, file…) through a\nseries of operations and produces a result. It **stores nothing**; it just\n*describes* a computation over the source.\n\nKey differences from a collection:\n\n| Collection | Stream |\n| ---------- | ------ |\n| Stores elements in memory | Holds no data — pulls from a source |\n| Eagerly built | **Lazily** evaluated |\n| Iterated externally (you loop) | Iterated internally (the stream loops) |\n| Reusable | **Single-use** (consumed once) |\n| Can be modified | Source is never mutated |\n\nSo you use a collection to *hold* data and a stream to *process* it\ndeclaratively (`filter` → `map` → `collect`) instead of writing explicit loops.\n",{"id":1934,"difficulty":113,"q":1935,"a":1936},"creating-streams","What are the common ways to create a Stream?","Streams come from many **sources**:\n\n```java\nlist.stream();                       \u002F\u002F from any Collection\nStream.of(\"a\", \"b\", \"c\");            \u002F\u002F from explicit values\nArrays.stream(new int[]{1, 2, 3});   \u002F\u002F from an array\nStream.iterate(1, n -> n * 2);       \u002F\u002F infinite: 1,2,4,8,...\nStream.generate(Math::random);       \u002F\u002F infinite: repeated supplier calls\nIntStream.range(0, 5);               \u002F\u002F 0,1,2,3,4 (range)\nIntStream.rangeClosed(1, 5);         \u002F\u002F 1,2,3,4,5 (inclusive)\nFiles.lines(Path.of(\"data.txt\"));    \u002F\u002F lazy stream of lines\n\"abc\".chars();                       \u002F\u002F IntStream of char codes\n```\n\n`Stream.iterate`\u002F`generate` are **infinite** — always pair them with a\nshort-circuiting op like `limit(n)`. `Files.lines` returns a stream backed by an\nopen file, so close it (use try-with-resources).\n",{"id":1938,"difficulty":105,"q":1939,"a":1940},"intermediate-vs-terminal","What is the difference between intermediate and terminal operations?","A stream pipeline is exactly **zero-or-more intermediate operations followed by\none terminal operation**.\n\n| | Intermediate | Terminal |\n| --- | ------------ | -------- |\n| Returns | another `Stream` | a value \u002F side-effect (not a stream) |\n| Evaluation | **lazy** — does nothing yet | **eager** — triggers the work |\n| Count per pipeline | any number | exactly one |\n| Examples | `filter`, `map`, `sorted`, `distinct`, `limit`, `peek` | `collect`, `forEach`, `reduce`, `count`, `findFirst`, `toArray` |\n\n```java\nlist.stream()\n    .filter(s -> s.length() > 3)   \u002F\u002F intermediate — lazy\n    .map(String::toUpperCase)      \u002F\u002F intermediate — lazy\n    .collect(Collectors.toList()); \u002F\u002F terminal — runs the pipeline\n```\n\nWithout a terminal operation **nothing executes** — the intermediate steps are\njust recorded.\n",{"id":1942,"difficulty":105,"q":1943,"a":1944},"laziness","What does it mean that streams are lazy?","**Laziness** means intermediate operations are not evaluated when they are\ncalled — they only run when a **terminal** operation demands elements. The\npipeline then processes elements **one at a time, vertically** (each element\nflows through all stages before the next starts), not stage-by-stage over the\nwhole collection.\n\n```java\nStream\u003CString> s = list.stream()\n    .filter(x -> { System.out.println(\"filter \" + x); return true; })\n    .map(x -> { System.out.println(\"map \" + x); return x; });\n\u002F\u002F nothing printed yet — no terminal op\ns.forEach(x -> {});   \u002F\u002F NOW it runs, interleaving \"filter a\", \"map a\", ...\n```\n\nLaziness enables two big wins: **fusion** (multiple ops run in one pass) and\n**short-circuiting** (the pipeline can stop early without touching every\nelement).\n",{"id":1946,"difficulty":105,"q":1947,"a":1948},"short-circuiting","What is short-circuiting in a stream pipeline?","A **short-circuiting** operation can produce a result (or stop the pipeline)\n**without processing every element**. Combined with laziness, this lets streams\nwork on **infinite** sources and quit as soon as the answer is known.\n\nShort-circuiting **terminal** ops: `findFirst`, `findAny`, `anyMatch`,\n`allMatch`, `noneMatch`. Short-circuiting **intermediate** op: `limit`.\n\n```java\nStream.iterate(1, n -> n + 1)   \u002F\u002F infinite\n      .filter(n -> n % 7 == 0)\n      .findFirst();             \u002F\u002F stops at 7 — never runs forever\n\nboolean any = list.stream().anyMatch(s -> s.isEmpty()); \u002F\u002F stops at first match\n```\n\n`allMatch` stops at the first element that **fails**, `anyMatch` at the first\nthat **passes** — they rarely scan the whole stream.\n",{"id":1950,"difficulty":113,"q":1951,"a":1952},"filter","What does the filter operation do?","**`filter`** is an intermediate operation that keeps only elements matching a\n**`Predicate`** (a function returning `boolean`); the rest are dropped. It does\nnot change the element type — only how many pass through.\n\n```java\nList\u003CString> longNames = names.stream()\n    .filter(n -> n.length() > 4)   \u002F\u002F keep names longer than 4 chars\n    .collect(Collectors.toList());\n```\n\n`filter` is **stateless** and lazy, so several filters fuse into one pass.\nRule of thumb: `filter` decides *whether* an element survives; `map` decides\n*what* it becomes.\n",{"id":1954,"difficulty":113,"q":1955,"a":1956},"map","What does the map operation do?","**`map`** is an intermediate operation that applies a **`Function`** to each\nelement and replaces it with the result — a **one-to-one transformation**. It can\nchange the element **type** (`Stream\u003CString>` → `Stream\u003CInteger>`).\n\n```java\nList\u003CInteger> lengths = names.stream()\n    .map(String::length)           \u002F\u002F String -> Integer\n    .collect(Collectors.toList());\n```\n\n`map` never changes the **number** of elements (N in, N out); it only transforms\neach one. When the mapping produces *another collection or stream* per element\nand you want them flattened, you need `flatMap` instead.\n",{"id":1958,"difficulty":126,"q":1959,"a":1960},"flatmap","What is flatMap and when do you use it instead of map?","**`flatMap`** maps each element to a **stream** and then **flattens** all those\nstreams into one. Use it when the mapping function yields multiple values per\nelement (a list, an `Optional`, a nested stream) and you want a single flat\nstream rather than a stream-of-streams.\n\n```java\nList\u003CList\u003CInteger>> nested = List.of(List.of(1, 2), List.of(3, 4));\n\n\u002F\u002F map gives Stream\u003CStream\u003CInteger>> — wrong shape\nnested.stream().map(List::stream);\n\n\u002F\u002F flatMap flattens to Stream\u003CInteger> -> [1, 2, 3, 4]\nList\u003CInteger> flat = nested.stream()\n    .flatMap(List::stream)\n    .collect(Collectors.toList());\n```\n\nMental model: use **`map`** for one-to-one (N→N), **`flatMap`** for one-to-many\nthat you want merged (N→M). Splitting sentences into words is the classic\n`flatMap` case.\n",{"id":1962,"difficulty":105,"q":1963,"a":1964},"distinct-sorted","What do distinct and sorted do, and what is special about them?","**`distinct`** removes duplicates (by `equals`\u002F`hashCode`); **`sorted`** orders\nelements (natural order, or a supplied `Comparator`). Both are intermediate but\n**stateful** — they must see elements before they can emit.\n\n```java\nnums.stream()\n    .distinct()                          \u002F\u002F drop duplicates\n    .sorted(Comparator.reverseOrder())   \u002F\u002F sort descending\n    .collect(Collectors.toList());\n```\n\n`sorted` is a **full barrier**: it buffers the entire stream before producing any\noutput, so it cannot short-circuit and **breaks on infinite streams**. Both add\nmemory and ordering overhead, so apply `filter` *before* them to shrink the work.\n",{"id":1966,"difficulty":113,"q":1967,"a":1968},"limit-skip","What do limit and skip do?","**`limit(n)`** truncates the stream to the first `n` elements;\n**`skip(n)`** discards the first `n` and keeps the rest. Together they give\npagination-style slicing.\n\n```java\nStream.iterate(1, x -> x + 1)\n      .limit(10)            \u002F\u002F first 10: 1..10\n      .skip(3)              \u002F\u002F drop 1,2,3 -> 4..10\n      .collect(Collectors.toList());\n```\n\n`limit` is **short-circuiting** — it's what tames infinite streams. On an\n**ordered** stream both are deterministic; on an unordered\u002Fparallel stream they\nmay pick *any* n elements, and `limit` on a parallel stream can actually hurt\nperformance because of the ordering constraint.\n",{"id":1970,"difficulty":105,"q":1971,"a":1972},"peek","What is peek used for and why is it controversial?","**`peek`** is an intermediate operation that runs a side-effecting action on each\nelement **as it flows past**, then passes the element through unchanged. Its\nintended use is **debugging** — logging what moves through each stage.\n\n```java\nlist.stream()\n    .peek(x -> System.out.println(\"before filter: \" + x))\n    .filter(x -> x > 2)\n    .peek(x -> System.out.println(\"after filter: \" + x))\n    .collect(Collectors.toList());\n```\n\nIt's controversial because (1) it's lazy, so elements skipped by\nshort-circuiting **never reach `peek`**, and (2) using it to *mutate* state is an\nanti-pattern. Rule of thumb: use `peek` only for observation, never for logic.\n",{"id":1974,"difficulty":126,"q":1975,"a":1976},"reduce","What is reduce and what are its three forms?","**`reduce`** combines all elements into a **single result** by repeatedly\napplying a binary operator. It comes in three overloads:\n\n```java\n\u002F\u002F 1. accumulator only -> Optional (stream may be empty)\nOptional\u003CInteger> sum = nums.stream().reduce((a, b) -> a + b);\n\n\u002F\u002F 2. identity + accumulator -> a plain value (identity if empty)\nint total = nums.stream().reduce(0, Integer::sum);\n\n\u002F\u002F 3. identity + accumulator + combiner -> for parallel \u002F type change\nint len = words.stream()\n    .reduce(0, (acc, w) -> acc + w.length(), Integer::sum);\n```\n\nThe **identity** must be a true no-op (`0` for sum, `1` for product). The\n**combiner** merges partial results from parallel sub-streams, so it's required\nwhen the accumulator's result type differs from the element type.\n",{"id":1978,"difficulty":113,"q":1979,"a":1980},"count-min-max","How do count, min, and max work as terminal operations?","**`count()`** returns the number of elements as a `long`. **`min`** and **`max`**\ntake a `Comparator` and return an **`Optional`** (empty if the stream is empty).\n\n```java\nlong n = list.stream().filter(s -> s.startsWith(\"a\")).count();\n\nOptional\u003CString> longest = list.stream()\n    .max(Comparator.comparingInt(String::length));\n\nint smallest = nums.stream().min(Integer::compareTo).orElse(0);\n```\n\n`min`\u002F`max` return `Optional` precisely because there's no sensible value for an\nempty stream — handle it with `orElse`\u002F`orElseThrow`. (Note: since Java 9 the JVM\nmay skip the pipeline for `count()` if it can compute the size directly.)\n",{"id":1982,"difficulty":105,"q":1983,"a":1984},"match-operations","What is the difference between anyMatch, allMatch and noneMatch?","All three are **short-circuiting** terminal operations that take a `Predicate`\nand return a `boolean`:\n\n- **`anyMatch`** — `true` if **at least one** element matches (stops at the\n  first match).\n- **`allMatch`** — `true` if **every** element matches (stops at the first\n  failure).\n- **`noneMatch`** — `true` if **no** element matches.\n\n```java\nnums.stream().anyMatch(n -> n \u003C 0);   \u002F\u002F any negatives?\nnums.stream().allMatch(n -> n > 0);   \u002F\u002F all positive?\nnums.stream().noneMatch(n -> n == 0); \u002F\u002F no zeros?\n```\n\nWatch the **empty-stream** edge cases (vacuous truth): on an empty stream\n`allMatch` and `noneMatch` return **`true`**, while `anyMatch` returns\n**`false`**.\n",{"id":1986,"difficulty":105,"q":1987,"a":1988},"findfirst-findany","What is the difference between findFirst and findAny?","Both return an **`Optional`** with *some* element (or empty), and both\nshort-circuit. The difference matters only in **parallel** streams:\n\n- **`findFirst`** — returns the **first element in encounter order**.\n- **`findAny`** — returns **any** element, whichever a worker thread finds\n  first. It frees the runtime from honoring order, so it can be faster in\n  parallel.\n\n```java\nOptional\u003CInteger> a = nums.stream().filter(n -> n > 10).findFirst();\nOptional\u003CInteger> b = nums.parallelStream().filter(n -> n > 10).findAny();\n```\n\nOn a sequential stream they behave identically. Use `findAny` when you genuinely\ndon't care *which* match you get and want maximum parallel performance.\n",{"id":1990,"difficulty":105,"q":1991,"a":1992},"collect-toarray-tolist","How do you turn a stream back into a collection or array?","The main terminal operation is **`collect`** with a `Collector`. There are also\ndirect helpers:\n\n```java\nList\u003CString> list = s.collect(Collectors.toList()); \u002F\u002F mutable-ish, classic\nList\u003CString> imm  = s.toList();                      \u002F\u002F Java 16+, unmodifiable\nSet\u003CString>  set  = s.collect(Collectors.toSet());\n\nString[]     arr  = s.toArray(String[]::new);        \u002F\u002F typed array\nObject[]     objs = s.toArray();                     \u002F\u002F Object[]\nint[]        ints = intStream.toArray();             \u002F\u002F primitive array\n```\n\n**`toList()`** (Java 16+) is the concise modern choice but returns an\n**unmodifiable** list; use `Collectors.toList()` if you need to mutate the\nresult. Pass a generator (`String[]::new`) to `toArray` to get a typed array\ninstead of `Object[]`. Deeper collector recipes (grouping, joining) live on the\nCollectors page.\n",{"id":1994,"difficulty":105,"q":1995,"a":1996},"primitive-streams","What are IntStream, LongStream and DoubleStream and why use them?","They are **specialized primitive streams** that avoid the boxing overhead of\n`Stream\u003CInteger>`\u002F`Stream\u003CLong>`\u002F`Stream\u003CDouble>`. Because elements are raw\nprimitives, they add numeric terminal ops that the object stream lacks.\n\n```java\nint sum      = IntStream.rangeClosed(1, 100).sum();\ndouble avg   = IntStream.of(1, 2, 3).average().orElse(0); \u002F\u002F OptionalDouble\nIntSummaryStatistics st = nums.stream()\n    .mapToInt(Integer::intValue)   \u002F\u002F Stream\u003CInteger> -> IntStream\n    .summaryStatistics();          \u002F\u002F count, sum, min, max, average at once\n```\n\nConvert with **`mapToInt`\u002F`mapToLong`\u002F`mapToDouble`** to enter a primitive\nstream, **`boxed()`** or **`mapToObj(...)`** to go back to an object stream.\nPrefer primitive streams for heavy numeric work — they're faster and offer\n`sum`\u002F`average`\u002F`summaryStatistics` for free.\n",{"id":1998,"difficulty":126,"q":1999,"a":2000},"stateless-vs-stateful","What is the difference between stateless and stateful operations?","A **stateless** operation processes each element **independently** of the others\n(`filter`, `map`, `flatMap`, `peek`) — it needs no memory of what came before.\nA **stateful** operation must consider **other elements** to produce its output\n(`distinct`, `sorted`, `limit`, `skip`).\n\n```java\nstream.filter(x -> x > 0)   \u002F\u002F stateless — each element judged alone\n      .sorted()             \u002F\u002F stateful — needs ALL elements buffered\n      .distinct();          \u002F\u002F stateful — must remember what it has seen\n```\n\nWhy it matters: stateful ops may **buffer** the stream (extra memory), can act as\n**barriers** that prevent short-circuiting (`sorted` on an infinite stream hangs),\nand are harder to **parallelize**. Keep pipelines stateless where you can.\n",{"id":2002,"difficulty":105,"q":2003,"a":2004},"stream-reuse","Why can't a stream be reused, and what happens if you try?","A stream can be **traversed only once**. After a terminal operation runs (or even\nafter some intermediate ops link onto it), the stream is **consumed**; touching it\nagain throws **`IllegalStateException: stream has already been operated upon or\nclosed`**.\n\n```java\nStream\u003CString> s = list.stream();\ns.count();          \u002F\u002F terminal — consumes the stream\ns.forEach(...);     \u002F\u002F IllegalStateException!\n```\n\nStreams are single-use because they hold no data and may be backed by I\u002FO or\ninfinite generators — re-traversal isn't generally possible. If you need to\nprocess the data twice, **re-create the stream from the source** (`list.stream()`\nagain) or use a `Supplier\u003CStream\u003CT>>` that builds a fresh one on demand.\n",{"id":2006,"difficulty":126,"q":2007,"a":2008},"parallel-streams","What are parallel streams and when do they help or hurt?","A **parallel stream** splits its source and processes chunks **concurrently** on\nthe common **ForkJoinPool**, then merges the partial results. You opt in with\n`collection.parallelStream()` or `.parallel()` on an existing stream.\n\n```java\nlong count = bigList.parallelStream()\n                    .filter(this::isExpensive)\n                    .count();\n```\n\nThey **help** when: the data set is large, the per-element work is genuinely\nexpensive (CPU-bound), the source splits cheaply (arrays, `ArrayList`), and\noperations are stateless. They **hurt** when: the data is small, the source is\nhard to split (`LinkedList`, I\u002FO streams), elements are cheap (split\u002Fmerge cost\ndominates), or you rely on order. Rule of thumb: stay sequential by default and\nonly parallelize after measuring a real win.\n",{"id":2010,"difficulty":126,"q":2011,"a":2012},"stream-side-effects","Why should you avoid side effects and stateful lambdas in streams?","Stream operations should be **pure** — depend only on their input and not mutate\nshared state. A **stateful lambda** that reads or writes outside variables breaks\nunder parallelism and even under reordering, producing **non-deterministic** or\ncorrupt results.\n\n```java\n\u002F\u002F BROKEN: shared mutable state, not thread-safe in parallel\nList\u003CInteger> out = new ArrayList\u003C>();\nnums.parallelStream().forEach(out::add);   \u002F\u002F data race \u002F lost updates\n\n\u002F\u002F CORRECT: let the framework collect for you\nList\u003CInteger> safe = nums.parallelStream()\n                         .collect(Collectors.toList());\n```\n\nAlso avoid modifying the stream's **source** during iteration\n(`ConcurrentModificationException`). Rule of thumb: never accumulate into an\nexternal collection from `forEach`\u002F`peek` — express the result with `collect`\nor `reduce`, which are designed to be safe even in parallel.\n",{"description":103},"Java Stream API interview questions — intermediate vs terminal operations, laziness and short-circuiting, map\u002Ffilter\u002Freduce, flatMap, stream sources, primitive streams, and parallel streams.","java\u002Fstreams-functional\u002Fstreams-api","Stream API","vyPHlLm8MySu2tJjaXRTbOKMIzsd3OepbddECXw20FU",{"id":2019,"title":2020,"body":2021,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":2025,"navigation":108,"order":38,"path":2026,"questions":2027,"questionsCount":805,"related":250,"seo":2116,"seoDescription":2117,"stem":2118,"subtopic":2020,"topic":46,"topicSlug":48,"updated":809,"__hash__":2119},"qa\u002Fjava\u002Fcollections\u002Fset-implementations.md","Set Implementations",{"type":100,"value":2022,"toc":2023},[],{"title":103,"searchDepth":29,"depth":29,"links":2024},[],{},"\u002Fjava\u002Fcollections\u002Fset-implementations",[2028,2032,2036,2040,2044,2048,2052,2056,2060,2064,2068,2072,2076,2080,2084,2088,2092,2096,2100,2104,2108,2112],{"id":2029,"difficulty":113,"q":2030,"a":2031},"set-contract","What is the Set interface and what is its core contract?","A `Set` is a `Collection` that holds **no duplicate elements** — adding an\nelement already present is a no-op and `add` returns `false`. There's no index\nand (for the general contract) no positional access; you check membership with\n`contains`, which is the operation sets are built to make fast.\n\n```java\nSet\u003CString> tags = new HashSet\u003C>();\ntags.add(\"java\");   \u002F\u002F true  — added\ntags.add(\"java\");   \u002F\u002F false — duplicate, ignored\ntags.size();        \u002F\u002F 1\ntags.contains(\"java\"); \u002F\u002F true\n```\n\n\"Duplicate\" is defined by **`equals`** (and `hashCode` for hash-based sets, or\n`compareTo`\u002F`Comparator` for sorted sets) — not by reference identity. That\ndefinition of equality is the heart of every Set question.\n",{"id":2033,"difficulty":105,"q":2034,"a":2035},"how-dedup-works","How does a Set decide that two elements are duplicates?","It depends on the implementation, and this is the single most important Set\ndetail in interviews:\n\n| Set | Duplicate test |\n| --- | -------------- |\n| `HashSet`, `LinkedHashSet` | `hashCode()` to find the bucket, then `equals()` within it |\n| `TreeSet` | `compareTo()` (or the supplied `Comparator`) — **`equals` is ignored** |\n\n```java\n\u002F\u002F Two elements are \"equal\" in a TreeSet when compare returns 0:\nSet\u003CString> ci = new TreeSet\u003C>(String.CASE_INSENSITIVE_ORDER);\nci.add(\"Java\");\nci.add(\"JAVA\");   \u002F\u002F compare == 0 -> treated as duplicate, not added\nci.size();        \u002F\u002F 1\n```\n\nThe trap: a `TreeSet` uses comparison, **not `equals`**, so an element can be\ndropped as a \"duplicate\" even though `equals` says it's different (and vice\nversa) — keep your `compareTo` *consistent with equals* to avoid surprises.\n",{"id":2037,"difficulty":105,"q":2038,"a":2039},"hashset-internals","How does HashSet work internally?","A `HashSet` is just a thin wrapper around a **`HashMap`** — each element is\nstored as a **key**, and all keys map to the same dummy `PRESENT` value object.\nSo everything you know about `HashMap` (buckets, load factor, treeified bins)\napplies directly.\n\n```java\n\u002F\u002F Conceptually, inside HashSet:\nprivate transient HashMap\u003CE, Object> map;\nprivate static final Object PRESENT = new Object();\n\npublic boolean add(E e) {\n    return map.put(e, PRESENT) == null; \u002F\u002F true if key was new\n}\n```\n\nThat's why `HashSet` gives **average O(1)** `add`\u002F`contains`\u002F`remove`, has **no\nordering**, and depends entirely on good `hashCode`\u002F`equals`. If hashes collide\nbadly, performance degrades toward O(n) (or O(log n) once a bucket treeifies).\n",{"id":2041,"difficulty":105,"q":2042,"a":2043},"linkedhashset","How is LinkedHashSet different from HashSet?","`LinkedHashSet` extends `HashSet` but is backed by a **`LinkedHashMap`**, so it\nkeeps a doubly-linked list threading through the entries. The effect:\niteration follows **insertion order** while keeping `HashSet`'s O(1) operations.\n\n```java\nSet\u003CString> hs = new HashSet\u003C>();\nhs.add(\"c\"); hs.add(\"a\"); hs.add(\"b\");\n\u002F\u002F iteration order: unspecified (e.g. a, b, c)\n\nSet\u003CString> lhs = new LinkedHashSet\u003C>();\nlhs.add(\"c\"); lhs.add(\"a\"); lhs.add(\"b\");\n\u002F\u002F iteration order: c, a, b  — exactly as inserted\n```\n\nCost is a slightly larger memory footprint (the extra prev\u002Fnext links). Reach\nfor it whenever you need **dedup but predictable, reproducible ordering** —\ne.g. removing duplicates from a list without scrambling it.\n",{"id":2045,"difficulty":105,"q":2046,"a":2047},"treeset-internals","How does TreeSet work and what ordering does it give?","A `TreeSet` is backed by a **`TreeMap`**, a **red-black tree** (self-balancing\nbinary search tree). Elements are kept in **sorted order** — natural ordering\nvia `Comparable`, or a `Comparator` you pass to the constructor — and core\noperations are **O(log n)** rather than O(1).\n\n```java\nSet\u003CInteger> nums = new TreeSet\u003C>();\nnums.add(5); nums.add(1); nums.add(3);\nSystem.out.println(nums);  \u002F\u002F [1, 3, 5] — always sorted\n\n\u002F\u002F custom order:\nSet\u003CString> byLen = new TreeSet\u003C>(Comparator.comparingInt(String::length));\n```\n\nBecause it's a tree, you get **range and neighbour queries** for free\n(`first`, `last`, `floor`, `ceiling`, `headSet`…). The trade-off vs `HashSet`:\nslower point lookups but ordered iteration and rich navigation.\n",{"id":2049,"difficulty":105,"q":2050,"a":2051},"treeset-requires-comparable","What does TreeSet require of its elements?","Elements must be **mutually comparable** — either they implement `Comparable`\n(natural ordering) or you supply a `Comparator`. Without one of those, the very\nfirst `add` of a non-comparable type throws `ClassCastException` at runtime.\n\n```java\nclass Point { int x, y; }              \u002F\u002F no Comparable, no Comparator\nSet\u003CPoint> s = new TreeSet\u003C>();\ns.add(new Point());                    \u002F\u002F ClassCastException at runtime\n\n\u002F\u002F fix: give it an ordering\nSet\u003CPoint> ok = new TreeSet\u003C>(Comparator.comparingInt(p -> p.x));\nok.add(new Point());                   \u002F\u002F fine\n```\n\nNote the failure is **not** at construction time — an empty `TreeSet` is happy;\nit only blows up when it needs to compare an element it can't order.\n",{"id":2053,"difficulty":105,"q":2054,"a":2055},"comparison-table","Compare HashSet, LinkedHashSet and TreeSet.","The classic side-by-side every interviewer expects:\n\n| Feature | `HashSet` | `LinkedHashSet` | `TreeSet` |\n| ------- | --------- | --------------- | --------- |\n| Backed by | `HashMap` | `LinkedHashMap` | `TreeMap` (red-black tree) |\n| Ordering | none | insertion order | sorted (natural\u002Fcomparator) |\n| `add`\u002F`contains`\u002F`remove` | O(1) avg | O(1) avg | O(log n) |\n| `null` allowed | one `null` | one `null` | **no** (NPE with natural order) |\n| Needs `equals`\u002F`hashCode` | yes | yes | uses `compareTo`\u002F`Comparator` |\n| Extra navigation | no | no | yes (`first`\u002F`floor`\u002F`subSet`…) |\n\n```java\n\u002F\u002F pick by need:\nnew HashSet\u003C>();        \u002F\u002F fastest, order doesn't matter\nnew LinkedHashSet\u003C>();  \u002F\u002F dedup, keep insertion order\nnew TreeSet\u003C>();        \u002F\u002F need sorted iteration or range queries\n```\n\nNone of the three is thread-safe. **Default to `HashSet`**; upgrade only when\nyou specifically need order or sorting.\n",{"id":2057,"difficulty":105,"q":2058,"a":2059},"sortedset-vs-navigableset","What is the difference between SortedSet and NavigableSet?","`SortedSet` is the older interface guaranteeing sorted iteration and offering\n`first()`, `last()`, `headSet`, `tailSet`, `subSet`, and `comparator()`.\n`NavigableSet` (Java 6+) **extends** it with neighbour lookups and\nreverse-order views. `TreeSet` implements both.\n\n```java\nNavigableSet\u003CInteger> s = new TreeSet\u003C>(List.of(10, 20, 30, 40));\ns.first();           \u002F\u002F 10        (SortedSet)\ns.last();            \u002F\u002F 40\ns.floor(25);         \u002F\u002F 20  \u003C= 25 (NavigableSet)\ns.ceiling(25);       \u002F\u002F 30  >= 25\ns.descendingSet();   \u002F\u002F [40, 30, 20, 10]\ns.pollFirst();       \u002F\u002F 10, and removes it\n```\n\nIn practice you usually just declare the variable as `NavigableSet` (or\n`TreeSet`) to get the full method set — `SortedSet` alone lacks the handy\n`floor`\u002F`ceiling`\u002F`higher`\u002F`lower` queries.\n",{"id":2061,"difficulty":126,"q":2062,"a":2063},"navigation-methods","What do floor, ceiling, higher and lower do on a NavigableSet?","They find the closest element to a target. The distinction is **inclusive vs\nexclusive** of the target itself:\n\n| Method | Returns |\n| ------ | ------- |\n| `floor(e)` | greatest element **≤ e** |\n| `ceiling(e)` | smallest element **≥ e** |\n| `lower(e)` | greatest element **strictly \u003C e** |\n| `higher(e)` | smallest element **strictly > e** |\n\n```java\nNavigableSet\u003CInteger> s = new TreeSet\u003C>(List.of(10, 20, 30));\ns.floor(20);   \u002F\u002F 20  (\u003C=)\ns.lower(20);   \u002F\u002F 10  (strictly \u003C)\ns.ceiling(20); \u002F\u002F 20  (>=)\ns.higher(20);  \u002F\u002F 30  (strictly >)\ns.floor(5);    \u002F\u002F null — nothing \u003C= 5\n```\n\nAll return `null` when no such element exists, so callers must null-check.\nThese run in **O(log n)** and are exactly why you reach for a `TreeSet` over a\n`HashSet` for \"nearest neighbour\" or range problems.\n",{"id":2065,"difficulty":126,"q":2066,"a":2067},"subset-views","What do headSet, tailSet and subSet return, and are they live views?","They return **range views** of a sorted set — not copies. `headSet(to)` is\neverything below `to`, `tailSet(from)` is everything from `from` up, and\n`subSet(from, to)` is the half-open range `[from, to)`. The `NavigableSet`\noverloads let you toggle the inclusive\u002Fexclusive bounds.\n\n```java\nNavigableSet\u003CInteger> s = new TreeSet\u003C>(List.of(10, 20, 30, 40));\ns.headSet(30);            \u002F\u002F [10, 20]      (exclusive end)\ns.tailSet(20);            \u002F\u002F [20, 30, 40]  (inclusive start)\ns.subSet(20, 40);         \u002F\u002F [20, 30]      (half-open)\ns.subSet(20, true, 40, true); \u002F\u002F [20, 30, 40]\n```\n\nThey are **backed by the original set**: changes flow both ways, and adding an\nelement outside the view's bounds throws `IllegalArgumentException`. Wrap in a\n`new TreeSet\u003C>(view)` if you need an independent snapshot.\n",{"id":2069,"difficulty":105,"q":2070,"a":2071},"descendingset","How do you iterate a TreeSet in reverse order?","Use `descendingSet()` (a reverse-ordered **view**) or `descendingIterator()`.\nBoth walk the tree from largest to smallest without copying or re-sorting.\n\n```java\nNavigableSet\u003CInteger> s = new TreeSet\u003C>(List.of(1, 2, 3));\nfor (int n : s.descendingSet()) {\n    System.out.print(n + \" \");   \u002F\u002F 3 2 1\n}\n\nIterator\u003CInteger> it = s.descendingIterator();\nwhile (it.hasNext()) { \u002F* 3, then 2, then 1 *\u002F }\n```\n\nBecause `descendingSet()` is a live view, mutations on it affect the original\nset and vice versa. It's the idiomatic alternative to constructing a\n`TreeSet` with `Comparator.reverseOrder()` when you only need reverse\niteration occasionally.\n",{"id":2073,"difficulty":105,"q":2074,"a":2075},"treeset-null","Can a TreeSet contain null?","No — with natural ordering, adding `null` throws **`NullPointerException`**,\nbecause the set must call `compareTo` on the element and `null.compareTo(...)`\ncan't happen. (A `HashSet`\u002F`LinkedHashSet`, by contrast, allows a single\n`null`.)\n\n```java\nSet\u003CString> tree = new TreeSet\u003C>();\ntree.add(null);   \u002F\u002F NullPointerException\n\nSet\u003CString> hash = new HashSet\u003C>();\nhash.add(null);   \u002F\u002F fine — exactly one null allowed\n```\n\nEven a null-tolerant `Comparator` (e.g. `Comparator.nullsFirst(...)`) only\nhelps for *non-first* elements; the first `add(null)` on an empty natural-order\n`TreeSet` still throws. Treat `TreeSet` as **null-hostile**.\n",{"id":2077,"difficulty":105,"q":2078,"a":2079},"enumset","What is EnumSet and why is it so fast?","`EnumSet` is a specialized `Set` for **enum** types only. Internally it's a\n**bit vector** — a single `long` (or array of `long`s for big enums) where each\nbit represents one constant. That makes operations near-instant and the memory\nfootprint tiny.\n\n```java\nenum Day { MON, TUE, WED, THU, FRI, SAT, SUN }\n\nEnumSet\u003CDay> work = EnumSet.range(Day.MON, Day.FRI);\nEnumSet\u003CDay> weekend = EnumSet.complementOf(work); \u002F\u002F [SAT, SUN]\nEnumSet\u003CDay> none = EnumSet.noneOf(Day.class);\nEnumSet\u003CDay> all  = EnumSet.allOf(Day.class);\n```\n\nIteration follows the enum's **declaration order**. It's created via factory\nmethods (`of`, `range`, `allOf`, `noneOf`, `complementOf`) rather than `new`.\nWhenever your set elements are enum constants, `EnumSet` beats `HashSet` on\nevery axis — speed, memory, and clarity.\n",{"id":2081,"difficulty":126,"q":2082,"a":2083},"set-thread-safety","How do you make a Set thread-safe?","The standard `HashSet`\u002F`TreeSet`\u002F`LinkedHashSet` are **not synchronized**.\nOptions, from cheap to concurrent:\n\n- **`Collections.synchronizedSet(set)`** — wraps every method in a lock; you\n  must still **manually synchronize** when *iterating*.\n- **`ConcurrentHashMap.newKeySet()`** — a concurrent hash set backed by\n  `ConcurrentHashMap`; high-throughput, no external locking, weakly consistent\n  iteration.\n- **`CopyOnWriteArraySet`** — copies the backing array on every write; great\n  for tiny, read-heavy sets, terrible for write-heavy ones.\n\n```java\nSet\u003CString> sync = Collections.synchronizedSet(new HashSet\u003C>());\nsynchronized (sync) {                \u002F\u002F iteration needs the lock\n    for (String s : sync) { \u002F* ... *\u002F }\n}\n\nSet\u003CString> concurrent = ConcurrentHashMap.newKeySet(); \u002F\u002F preferred default\n```\n\nFor most concurrent code, **`ConcurrentHashMap.newKeySet()`** is the right\nchoice — it scales far better than a globally locked wrapper.\n",{"id":2085,"difficulty":126,"q":2086,"a":2087},"copyonwritearrayset","When would you use CopyOnWriteArraySet?","`CopyOnWriteArraySet` (backed by a `CopyOnWriteArrayList`) makes a **fresh copy\nof the whole array on every mutation**. Reads and iteration are lock-free and\nsee a stable snapshot, but each `add`\u002F`remove` is **O(n)**.\n\n```java\nSet\u003CListener> listeners = new CopyOnWriteArraySet\u003C>();\nlisteners.add(a);                 \u002F\u002F copies the backing array\nfor (Listener l : listeners) {    \u002F\u002F iterates a snapshot — no CME, ever\n    l.onEvent();                  \u002F\u002F safe even if another thread mutates\n}\n```\n\nIt shines for **small, read-mostly, rarely-mutated** sets — the textbook case\nbeing event-listener registries. Because it scans the array, `contains` is\nO(n), so it's a poor fit for large or write-heavy sets, where\n`ConcurrentHashMap.newKeySet()` wins.\n",{"id":2089,"difficulty":113,"q":2090,"a":2091},"set-union","How do you compute the union of two sets?","Copy one set and `addAll` the other — duplicates are dropped automatically by\nthe Set contract.\n\n```java\nSet\u003CInteger> a = new HashSet\u003C>(List.of(1, 2, 3));\nSet\u003CInteger> b = new HashSet\u003C>(List.of(3, 4, 5));\n\nSet\u003CInteger> union = new HashSet\u003C>(a);\nunion.addAll(b);          \u002F\u002F {1, 2, 3, 4, 5}\n```\n\n`addAll` is the **union** operator. Always copy first (`new HashSet\u003C>(a)`) so\nyou don't mutate the original `a` — a common bug is calling `a.addAll(b)` and\nsilently changing the caller's set.\n",{"id":2093,"difficulty":113,"q":2094,"a":2095},"set-intersection","How do you compute the intersection of two sets?","`retainAll` keeps only the elements present in **both** sets.\n\n```java\nSet\u003CInteger> a = new HashSet\u003C>(List.of(1, 2, 3));\nSet\u003CInteger> b = new HashSet\u003C>(List.of(3, 4, 5));\n\nSet\u003CInteger> intersection = new HashSet\u003C>(a);\nintersection.retainAll(b);   \u002F\u002F {3}\n```\n\n`retainAll` is the **intersection** operator. For performance, copy and iterate\nthe **smaller** set against the larger one — the cost is roughly\nO(min(a, b)) lookups, and lookups are O(1) on a `HashSet`.\n",{"id":2097,"difficulty":113,"q":2098,"a":2099},"set-difference","How do you compute the difference between two sets?","`removeAll` strips out every element that also appears in the other set,\nleaving the **difference** (elements in `a` but not `b`).\n\n```java\nSet\u003CInteger> a = new HashSet\u003C>(List.of(1, 2, 3));\nSet\u003CInteger> b = new HashSet\u003C>(List.of(3, 4, 5));\n\nSet\u003CInteger> diff = new HashSet\u003C>(a);\ndiff.removeAll(b);    \u002F\u002F {1, 2}\n```\n\nSo the trio is: **`addAll` = union, `retainAll` = intersection,\n`removeAll` = difference**. A symmetric difference (in either but not both) is\njust union minus intersection, or two `removeAll`s combined.\n",{"id":2101,"difficulty":126,"q":2102,"a":2103},"mutable-element-breaks-hashset","Why can mutating an element break a HashSet?","A `HashSet` places each element in a **bucket chosen by its `hashCode()` at\ninsertion time**. If you then mutate a field that `hashCode`\u002F`equals` depend\non, the element's hash changes but it stays in the *old* bucket — so the set\ncan no longer find it.\n\n```java\nSet\u003CPoint> set = new HashSet\u003C>();\nPoint p = new Point(1, 1);\nset.add(p);\np.x = 99;                  \u002F\u002F mutated a field used by hashCode\n\nset.contains(p);           \u002F\u002F false — looks in the new bucket, finds nothing\n\u002F\u002F p is now a \"ghost\": present but unreachable; even remove() may miss it\n```\n\nThat's why Set (and Map-key) elements should be **immutable**, or at least\nnever mutated on their `equals`\u002F`hashCode` fields while stored. It's the same\nreason `String` and the wrapper types — immutable — make perfect set elements.\n",{"id":2105,"difficulty":105,"q":2106,"a":2107},"immutable-set-of","What does Set.of return and what happens with duplicates?","`Set.of(...)` (Java 9+) returns a small, **immutable** set. Any mutating call\n(`add`, `remove`, `clear`) throws `UnsupportedOperationException`, and — unlike\na normal `add` that silently ignores dups — passing a **duplicate to the\nfactory throws `IllegalArgumentException`**.\n\n```java\nSet\u003CString> s = Set.of(\"a\", \"b\", \"c\");\ns.add(\"d\");                    \u002F\u002F UnsupportedOperationException\n\nSet\u003CString> dup = Set.of(\"a\", \"a\");  \u002F\u002F IllegalArgumentException at creation!\n```\n\nIt also **rejects `null`** (NPE) and has an **unspecified iteration order**\nthat can vary between runs. Use it for compact, never-changing constant sets;\nuse `LinkedHashSet`\u002F`TreeSet` when you need order or mutability.\n",{"id":2109,"difficulty":105,"q":2110,"a":2111},"set-iteration-order","What ordering guarantees do the different Sets give during iteration?","Each implementation makes a different promise — knowing them prevents a class\nof \"works on my machine\" bugs:\n\n| Set | Iteration order |\n| --- | --------------- |\n| `HashSet` | **no guarantee** (can even change between JVM runs) |\n| `LinkedHashSet` | insertion order |\n| `TreeSet` | sorted (natural or comparator) |\n| `EnumSet` | enum declaration order |\n| `Set.of(...)` | unspecified, may vary per run |\n\n```java\n\u002F\u002F never rely on HashSet order:\nfor (String s : new HashSet\u003C>(List.of(\"a\", \"b\", \"c\"))) { \u002F* any order *\u002F }\n```\n\nThe rule of thumb: if your output or tests depend on order, **don't use\n`HashSet`** — choose `LinkedHashSet` for insertion order or `TreeSet` for\nsorted order.\n",{"id":2113,"difficulty":105,"q":2114,"a":2115},"contains-performance","Why is HashSet.contains so much faster than List.contains?","`HashSet.contains` hashes the element, jumps straight to one bucket, and checks\nonly the few items there — **average O(1)**. `List.contains` has no index into\nits data, so it scans from the front comparing each element — **O(n)**.\n\n```java\nList\u003CInteger> list = new ArrayList\u003C>(\u002F* 1_000_000 items *\u002F);\nSet\u003CInteger> set  = new HashSet\u003C>(list);\n\nlist.contains(999_999);   \u002F\u002F O(n) — walks ~a million elements\nset.contains(999_999);    \u002F\u002F O(1) — one bucket lookup\n```\n\nThis is why a frequent pattern is to **dump a list into a `HashSet` first** when\nyou'll do many membership checks. The rule of thumb: need fast \"is it in\nthere?\" — use a `Set`, not a `List`.\n",{"description":103},"Java Set interview questions — HashSet vs LinkedHashSet vs TreeSet, how they work internally, ordering and complexity, NavigableSet\u002FSortedSet, EnumSet and CopyOnWriteArraySet, and set operations.","java\u002Fcollections\u002Fset-implementations","CPWBeux7ocEGdCEYbf-oLAL2c2Pl2DvsbAXeVO6qsB0",{"id":2121,"title":2122,"body":2123,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":2127,"navigation":108,"order":38,"path":2128,"questions":2129,"questionsCount":904,"related":250,"seo":2213,"seoDescription":2214,"stem":2215,"subtopic":2216,"topic":72,"topicSlug":74,"updated":809,"__hash__":2217},"qa\u002Fjava\u002Fconcurrency\u002Fexecutors-thread-pools.md","Executors Thread Pools",{"type":100,"value":2124,"toc":2125},[],{"title":103,"searchDepth":29,"depth":29,"links":2126},[],{},"\u002Fjava\u002Fconcurrency\u002Fexecutors-thread-pools",[2130,2134,2138,2142,2146,2150,2154,2158,2162,2166,2170,2174,2178,2182,2186,2190,2194,2198,2202,2206,2210],{"id":2131,"difficulty":105,"q":2132,"a":2133},"why-thread-pools","Why use a thread pool instead of creating a new thread per task?","Creating a thread is **expensive** — each one needs a stack (often ~512KB–1MB),\na kernel scheduling entry, and OS bookkeeping. Spawning one per task means\nunbounded thread creation under load, which exhausts memory and thrashes the\nscheduler. A **thread pool** reuses a fixed set of worker threads to run many\ntasks, so you pay the creation cost once and **bound resource usage**.\n\n```java\n\u002F\u002F anti-pattern: a new OS thread per request — no limit, no reuse\nfor (Runnable task : tasks) new Thread(task).start();\n\n\u002F\u002F pooled: a bounded set of workers pulls tasks off a queue\nExecutorService pool = Executors.newFixedThreadPool(8);\nfor (Runnable task : tasks) pool.submit(task);\n```\n\nThe two wins interviewers want: **reuse** (amortize thread cost) and **bounding**\n(a cap on concurrency so a spike can't take down the JVM). The pool also\ndecouples *task submission* from *task execution*.\n",{"id":2135,"difficulty":105,"q":2136,"a":2137},"executor-hierarchy","What is the Executor \u002F ExecutorService \u002F ScheduledExecutorService hierarchy?","They form a layered interface stack, each adding capability:\n\n- **`Executor`** — the minimal contract: a single `execute(Runnable)` method.\n  It just *runs* a task; how (now, pooled, async) is the implementation's choice.\n- **`ExecutorService`** — extends `Executor` with **lifecycle** (`shutdown`,\n  `awaitTermination`) and **result-bearing** submission (`submit`, `invokeAll`,\n  `invokeAny`) that return `Future`s.\n- **`ScheduledExecutorService`** — extends `ExecutorService` to run tasks\n  **after a delay** or **periodically** (`schedule`, `scheduleAtFixedRate`).\n\n```java\nExecutor e = Runnable::run;                       \u002F\u002F simplest possible Executor\nExecutorService es = Executors.newFixedThreadPool(4);\nScheduledExecutorService ses = Executors.newScheduledThreadPool(2);\n```\n\nYou almost always program against **`ExecutorService`** — it gives you both task\nresults and a way to shut the pool down cleanly.\n",{"id":2139,"difficulty":105,"q":2140,"a":2141},"executors-factory-methods","What thread pools do the Executors factory methods create?","`Executors` is a factory of preconfigured `ExecutorService`s:\n\n| Method | Behavior |\n| ------ | -------- |\n| `newFixedThreadPool(n)` | `n` fixed threads, **unbounded** task queue |\n| `newCachedThreadPool()` | grows on demand, idle threads die after 60s, **no queue** (synchronous handoff) |\n| `newSingleThreadExecutor()` | one thread, tasks run **sequentially**, unbounded queue |\n| `newScheduledThreadPool(n)` | `n` threads for delayed\u002Fperiodic tasks |\n| `newWorkStealingPool()` | a `ForkJoinPool` sized to CPUs, work-stealing |\n| `newVirtualThreadPerTaskExecutor()` | a new **virtual thread** per task (Java 21+) |\n\n```java\nExecutorService fixed  = Executors.newFixedThreadPool(8);\nExecutorService cached = Executors.newCachedThreadPool();\n```\n\nEach is just a `ThreadPoolExecutor` (or `ForkJoinPool`) with specific defaults —\nknowing those defaults explains the pitfalls in the next question.\n",{"id":2143,"difficulty":126,"q":2144,"a":2145},"why-executors-discouraged","Why is using Executors.* often discouraged in favor of ThreadPoolExecutor?","The convenience factories hide **dangerous defaults** that can cause\n`OutOfMemoryError` under load:\n\n- `newFixedThreadPool` \u002F `newSingleThreadExecutor` use an **unbounded\n  `LinkedBlockingQueue`** — if tasks arrive faster than they finish, the queue\n  grows without limit until the heap is exhausted.\n- `newCachedThreadPool` has **no upper bound on threads** — a burst can spawn\n  thousands of threads and run the machine out of native memory.\n\n```java\n\u002F\u002F explicit, safe: bounded queue + bounded threads + an explicit reject policy\nExecutorService pool = new ThreadPoolExecutor(\n    8, 16, 60L, TimeUnit.SECONDS,\n    new ArrayBlockingQueue\u003C>(1000),          \u002F\u002F bounded queue\n    new ThreadPoolExecutor.CallerRunsPolicy() \u002F\u002F backpressure on overflow\n);\n```\n\nEffective Java's guidance is to **construct `ThreadPoolExecutor` directly** so\nevery parameter (queue bound, max threads, rejection behavior) is a deliberate\ndecision rather than a hidden default.\n",{"id":2147,"difficulty":126,"q":2148,"a":2149},"threadpoolexecutor-params","What are the core constructor parameters of ThreadPoolExecutor?","`ThreadPoolExecutor` has six knobs that fully define its behavior:\n\n| Parameter | Meaning |\n| --------- | ------- |\n| `corePoolSize` | threads kept alive even when idle |\n| `maximumPoolSize` | hard cap on total threads |\n| `keepAliveTime` | how long **non-core** idle threads survive before dying |\n| `workQueue` | the `BlockingQueue` that holds waiting tasks |\n| `threadFactory` | creates worker threads (name them, set daemon\u002Fpriority) |\n| `handler` | `RejectedExecutionHandler` for when the pool is saturated |\n\n```java\nnew ThreadPoolExecutor(\n    4,                                  \u002F\u002F corePoolSize\n    10,                                 \u002F\u002F maximumPoolSize\n    30L, TimeUnit.SECONDS,              \u002F\u002F keepAliveTime\n    new ArrayBlockingQueue\u003C>(100),      \u002F\u002F workQueue\n    new CustomThreadFactory(\"worker\"),  \u002F\u002F threadFactory\n    new ThreadPoolExecutor.AbortPolicy()\u002F\u002F handler\n);\n```\n\nAlways supply a **named `ThreadFactory`** in production — default thread names\nlike `pool-1-thread-3` make stack traces and thread dumps nearly useless.\n",{"id":2151,"difficulty":126,"q":2152,"a":2153},"task-flow","How does a task flow through core pool, queue and max pool?","`ThreadPoolExecutor` applies a strict, sometimes surprising, order on `execute`:\n\n1. If running threads **\u003C `corePoolSize`**, start a **new core thread** for the\n   task (even if other threads are idle).\n2. Else, try to **enqueue** the task in the `workQueue`.\n3. Only if the **queue is full** does it create threads up to `maximumPoolSize`.\n4. If the queue is full **and** threads are at max, the task is **rejected**.\n\n```java\n\u002F\u002F core=2, queue=2, max=4 -> capacity surfaces in this order:\n\u002F\u002F tasks 1-2  -> run on 2 core threads\n\u002F\u002F tasks 3-4  -> wait in the queue (size 2)\n\u002F\u002F tasks 5-6  -> spawn 2 extra threads (up to max=4)\n\u002F\u002F task  7    -> rejected\n```\n\nThe non-obvious consequence: with an **unbounded queue**, step 3 never triggers,\nso `maximumPoolSize` is **ignored** and the pool never grows past core. This is\nexactly why `newFixedThreadPool` only ever runs `n` threads.\n",{"id":2155,"difficulty":126,"q":2156,"a":2157},"rejection-policies","What are the four rejection policies and when is a task rejected?","A task is **rejected** when the queue is full *and* the pool is at\n`maximumPoolSize` (or after shutdown). The `RejectedExecutionHandler` decides\nwhat happens:\n\n| Policy | Behavior |\n| ------ | -------- |\n| `AbortPolicy` (default) | throws `RejectedExecutionException` |\n| `CallerRunsPolicy` | runs the task on the **submitting thread** (natural backpressure) |\n| `DiscardPolicy` | silently drops the task |\n| `DiscardOldestPolicy` | drops the **oldest queued** task, retries the new one |\n\n```java\nvar pool = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS,\n    new ArrayBlockingQueue\u003C>(10),\n    new ThreadPoolExecutor.CallerRunsPolicy());\n```\n\n`CallerRunsPolicy` is the favorite for throughput-with-stability: when the pool\nis overwhelmed, the producer is *slowed down* (it executes the task itself)\ninstead of either throwing or losing work. You can also implement your own\nhandler to log, meter, or persist rejected tasks.\n",{"id":2159,"difficulty":126,"q":2160,"a":2161},"sizing-pools","How do you size a thread pool for CPU-bound vs IO-bound work?","The right size depends on what threads spend their time doing:\n\n- **CPU-bound** work keeps the core busy, so more threads than cores just adds\n  context-switching overhead. Size ≈ **number of cores** (sometimes `cores + 1`\n  to cover the occasional page fault).\n- **IO-bound** work blocks on network\u002Fdisk, leaving the CPU idle, so you want\n  **many more threads than cores** to keep the CPU saturated.\n\nA useful formula (Brian Goetz): `threads = cores × (1 + waitTime \u002F computeTime)`.\n\n```java\nint cores = Runtime.getRuntime().availableProcessors();\nExecutorService cpuPool = Executors.newFixedThreadPool(cores);     \u002F\u002F CPU-bound\nExecutorService ioPool  = Executors.newFixedThreadPool(cores * 8); \u002F\u002F IO-bound (illustrative)\n```\n\nTreat the formula as a **starting point** — measure throughput and latency under\nrealistic load and tune. (For heavily IO-bound work on Java 21+, **virtual\nthreads** sidestep sizing entirely.)\n",{"id":2163,"difficulty":105,"q":2164,"a":2165},"submit-vs-execute","What is the difference between submit() and execute()?","`execute(Runnable)` comes from `Executor` and returns **`void`** — it's\nfire-and-forget. `submit(...)` comes from `ExecutorService`, accepts a\n`Runnable` *or* `Callable`, and returns a **`Future`** you can use to get the\nresult, wait for completion, or cancel.\n\n```java\npool.execute(() -> log(\"done\"));        \u002F\u002F void, no handle\n\nFuture\u003CInteger> f = pool.submit(() -> 42); \u002F\u002F Future handle\nInteger result = f.get();                  \u002F\u002F 42\n```\n\nA subtle but important difference for debugging: with `execute`, an uncaught\nexception propagates to the thread's **`UncaughtExceptionHandler`** (you see it).\nWith `submit`, the exception is **captured inside the `Future`** and only\nsurfaces when you call `get()` — so a `submit`ted task that throws can fail\n**silently** if you never inspect the `Future`.\n",{"id":2167,"difficulty":105,"q":2168,"a":2169},"runnable-vs-callable","What is the difference between Runnable and Callable?","Both represent a unit of work, but:\n\n- **`Runnable`** — `void run()`, **cannot return a value**, and **cannot throw\n  checked exceptions**.\n- **`Callable\u003CV>`** — `V call() throws Exception`, **returns a result** and **may\n  throw checked exceptions**.\n\n```java\nRunnable r = () -> System.out.println(\"side effect only\");\nCallable\u003CInteger> c = () -> {\n    if (bad) throw new IOException(\"checked exception is fine here\");\n    return compute();                 \u002F\u002F returns a value\n};\nFuture\u003CInteger> f = pool.submit(c);\n```\n\nUse `Callable` when the task **produces a result** or might throw a checked\nexception. You can adapt a `Runnable` to a `Callable` via\n`Executors.callable(runnable)`.\n",{"id":2171,"difficulty":105,"q":2172,"a":2173},"future","What is a Future and what can you do with it?","A `Future\u003CV>` is a **handle to a result that may not exist yet** — the receipt\nyou get back from `submit`. Its key methods:\n\n- `get()` — **blocks** until the task completes and returns the result (or the\n  timed `get(timeout, unit)` variant).\n- `isDone()` — non-blocking check for completion.\n- `cancel(mayInterruptIfRunning)` — attempts to cancel; `isCancelled()` reports it.\n\n```java\nFuture\u003CInteger> f = pool.submit(() -> slowComputation());\nif (!f.isDone()) doOtherWork();\ntry {\n    Integer v = f.get(2, TimeUnit.SECONDS); \u002F\u002F wait up to 2s\n} catch (TimeoutException te) {\n    f.cancel(true);                          \u002F\u002F give up, interrupt the task\n}\n```\n\nThe classic limitation: a plain `Future` has **no callbacks** — you can only\n*poll* `isDone()` or *block* on `get()`. That gap is what `CompletableFuture`\nfills.\n",{"id":2175,"difficulty":126,"q":2176,"a":2177},"future-exceptions","How are exceptions from a submitted task surfaced?","If a task throws, the exception is **stored in the `Future`** and re-thrown,\n**wrapped in an `ExecutionException`**, when you call `get()`. The original cause\nis available via `getCause()`.\n\n```java\nFuture\u003CInteger> f = pool.submit(() -> { throw new IllegalStateException(\"boom\"); });\ntry {\n    f.get();\n} catch (ExecutionException e) {\n    Throwable cause = e.getCause();   \u002F\u002F the original IllegalStateException\n} catch (InterruptedException e) {\n    Thread.currentThread().interrupt(); \u002F\u002F restore the interrupt flag\n}\n```\n\nTwo interview points: `get()` declares both **`ExecutionException`** (task threw)\nand **`InterruptedException`** (the waiting thread was interrupted), and you must\nunwrap `getCause()` to see what actually went wrong. A task whose result you\nnever `get()` can swallow its failure entirely.\n",{"id":2179,"difficulty":105,"q":2180,"a":2181},"invokeall-invokeany","What do invokeAll and invokeAny do?","Both submit a **collection of `Callable`s** at once and block:\n\n- **`invokeAll`** runs **all** tasks and returns a `List\u003CFuture>` once **every**\n  task has finished (each `Future` is already complete).\n- **`invokeAny`** returns the result of the **first** task to complete\n  successfully, then **cancels the rest** — great for racing redundant lookups.\n\n```java\nList\u003CCallable\u003CInteger>> tasks = List.of(() -> 1, () -> 2, () -> 3);\n\nList\u003CFuture\u003CInteger>> all = pool.invokeAll(tasks); \u002F\u002F waits for all 3\nfor (Future\u003CInteger> f : all) use(f.get());\n\nInteger fastest = pool.invokeAny(tasks); \u002F\u002F first success, others cancelled\n```\n\nBoth have **timeout overloads**. With `invokeAll`, any task that fails surfaces\nonly when you call `get()` on its `Future`; `invokeAny` throws\n`ExecutionException` only if **every** task fails.\n",{"id":2183,"difficulty":126,"q":2184,"a":2185},"completablefuture-intro","What problem does CompletableFuture solve over Future?","A plain `Future` can only be **polled or blocked on** — you can't attach a\ncontinuation or compose multiple async results without blocking a thread.\n`CompletableFuture` (Java 8+) implements `CompletionStage`, adding a fluent,\n**non-blocking, callback-driven** pipeline.\n\n```java\nCompletableFuture\n    .supplyAsync(() -> fetchUser(id))       \u002F\u002F run async, returns a stage\n    .thenApply(User::name)                  \u002F\u002F transform the result\n    .thenAccept(System.out::println)        \u002F\u002F consume it, no blocking\n    .exceptionally(ex -> { log(ex); return null; }); \u002F\u002F handle failure\n```\n\nYou can **chain** transformations, **combine** independent futures, and **handle\nerrors** declaratively — turning callback spaghetti into a readable flow.\n`supplyAsync`\u002F`runAsync` use the **common ForkJoinPool** by default; pass your own\n`Executor` for control over which pool runs the work.\n",{"id":2187,"difficulty":126,"q":2188,"a":2189},"completablefuture-chaining","What is the difference between thenApply, thenCompose and thenCombine?","They cover the three common composition shapes:\n\n- **`thenApply(fn)`** — transform the result with a **plain function**\n  (`T -> U`). Result is `CompletableFuture\u003CU>`.\n- **`thenCompose(fn)`** — chain a function that **itself returns a future**\n  (`T -> CompletableFuture\u003CU>`); it **flattens**, avoiding a nested\n  `CompletableFuture\u003CCompletableFuture\u003CU>>`. This is the async \"flatMap\".\n- **`thenCombine(other, bifn)`** — wait for **two independent** futures and\n  **merge** their results.\n\n```java\ncf.thenApply(x -> x + 1);                       \u002F\u002F sync transform\ncf.thenCompose(id -> fetchAsync(id));           \u002F\u002F chain dependent async call\ncf1.thenCombine(cf2, (a, b) -> a + b);          \u002F\u002F join two parallel results\n```\n\nRule of thumb: use **`thenApply`** for a sync mapping, **`thenCompose`** when the\nmapping is *itself* async, and **`thenCombine`** to fan two parallel results back\ntogether.\n",{"id":2191,"difficulty":105,"q":2192,"a":2193},"completablefuture-errors","How do you handle errors in a CompletableFuture pipeline?","Three methods catch failures that propagate down the chain:\n\n- **`exceptionally(fn)`** — runs **only on failure**, supplying a fallback value\n  (`Throwable -> T`).\n- **`handle(bifn)`** — runs on **both** success and failure\n  (`(T result, Throwable ex) -> U`), so you can recover or transform either way.\n- **`whenComplete(bifn)`** — a **side-effect** callback on completion that does\n  **not** alter the result (good for logging\u002Fcleanup).\n\n```java\ncf.thenApply(this::risky)\n  .exceptionally(ex -> DEFAULT)              \u002F\u002F fallback on error only\n  .handle((res, ex) -> ex != null ? -1 : res) \u002F\u002F see both outcomes\n  .whenComplete((res, ex) -> log(res, ex));   \u002F\u002F observe, don't change\n```\n\nNote that exceptions arrive **wrapped in `CompletionException`** (use\n`getCause()`), and `exceptionally` recovers the chain so later stages see the\nfallback value rather than the error.\n",{"id":2195,"difficulty":105,"q":2196,"a":2197},"completablefuture-allof-anyof","What do CompletableFuture.allOf and anyOf do?","They aggregate **multiple** futures:\n\n- **`allOf(cf...)`** — completes when **all** given futures complete. It returns\n  `CompletableFuture\u003CVoid>`, so you join, then read each future's result\n  individually.\n- **`anyOf(cf...)`** — completes when the **first** of them completes, carrying\n  that future's result (as `Object`).\n\n```java\nCompletableFuture\u003CString> a = supplyAsync(() -> callA());\nCompletableFuture\u003CString> b = supplyAsync(() -> callB());\n\nCompletableFuture.allOf(a, b).join();        \u002F\u002F wait for both\nString combined = a.join() + b.join();       \u002F\u002F now safe, both done\n\nObject first = CompletableFuture.anyOf(a, b).join(); \u002F\u002F first to finish\n```\n\nBecause `allOf` yields `Void`, the idiom is to `join()` it as a barrier and then\npull each individual result — frequently done by collecting a list of futures\nand `allOf`-ing the array.\n",{"id":2199,"difficulty":126,"q":2200,"a":2201},"shutdown-vs-shutdownnow","What is the difference between shutdown, shutdownNow and awaitTermination?","An `ExecutorService` keeps its threads alive (often non-daemon) until you stop\nit, so you **must** shut it down or the JVM may never exit:\n\n- **`shutdown()`** — graceful: stops accepting new tasks but **lets already\n  submitted tasks finish**. Returns immediately.\n- **`shutdownNow()`** — aggressive: **interrupts** running tasks, **drains** the\n  queue, and returns the list of tasks that never started.\n- **`awaitTermination(timeout, unit)`** — **blocks** until the pool has\n  terminated or the timeout elapses; returns `true` if it terminated.\n\n```java\npool.shutdown();\nif (!pool.awaitTermination(30, TimeUnit.SECONDS)) {\n    pool.shutdownNow(); \u002F\u002F force the stragglers\n}\n```\n\nNeither `shutdown` method blocks on its own — `awaitTermination` is how you\nactually *wait*. And `shutdownNow` only **requests** interruption; tasks that\nignore the interrupt flag keep running.\n",{"id":2203,"difficulty":126,"q":2204,"a":2205},"graceful-shutdown-pattern","What is the recommended graceful shutdown pattern for an executor?","The canonical two-phase pattern (straight from the `ExecutorService` Javadoc):\nask politely, wait, then force, and **restore the interrupt** if you're\ninterrupted while waiting.\n\n```java\nvoid shutdownAndAwait(ExecutorService pool) {\n    pool.shutdown();                       \u002F\u002F stop taking new tasks\n    try {\n        if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {\n            pool.shutdownNow();            \u002F\u002F cancel in-flight tasks\n            if (!pool.awaitTermination(60, TimeUnit.SECONDS))\n                log(\"pool did not terminate\");\n        }\n    } catch (InterruptedException ie) {\n        pool.shutdownNow();\n        Thread.currentThread().interrupt(); \u002F\u002F preserve interrupt status\n    }\n}\n```\n\nWire this into a JVM shutdown hook or your framework's lifecycle. The key habits:\n**two await phases**, escalate from `shutdown` to `shutdownNow`, and never swallow\n`InterruptedException` — re-set the flag.\n",{"id":2207,"difficulty":105,"q":2208,"a":2209},"scheduledexecutorservice","How does ScheduledExecutorService schedule periodic tasks?","It runs tasks after a delay or repeatedly, replacing the legacy `Timer`\u002F\n`TimerTask` (which used a single thread and let one failing task kill all others):\n\n- **`schedule(task, delay, unit)`** — run **once** after a delay.\n- **`scheduleAtFixedRate(task, initial, period, unit)`** — start each run every\n  `period` **from the start of the previous run** (fixed cadence).\n- **`scheduleWithFixedDelay(task, initial, delay, unit)`** — wait `delay` **after\n  each run finishes** before the next starts.\n\n```java\nvar ses = Executors.newScheduledThreadPool(2);\nses.scheduleAtFixedRate(this::poll, 0, 5, TimeUnit.SECONDS);   \u002F\u002F every 5s\nses.scheduleWithFixedDelay(this::cleanup, 1, 10, TimeUnit.SECONDS);\n```\n\nThe crucial difference: **fixed-rate** can let runs bunch up (or overlap\nconceptually) if a task runs longer than the period, while **fixed-delay**\nguarantees a gap between runs. Also note an **uncaught exception silently\ncancels** all future executions of that scheduled task.\n",{"id":396,"difficulty":126,"q":2211,"a":2212},"How do virtual threads change thread-pool thinking in Java 21?","**Virtual threads** (Java 21, JEP 444) are lightweight threads managed by the JVM,\nnot 1:1 with OS threads. They're so cheap (a few hundred bytes) that you can have\n**millions**, and a blocking call **unmounts** the virtual thread from its\ncarrier OS thread instead of blocking it.\n\n```java\n\u002F\u002F one virtual thread per task — no pooling, no sizing\ntry (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n    for (var task : tasks) executor.submit(task);\n} \u002F\u002F try-with-resources auto-closes (shutdown + await)\n```\n\nThis upends the classic advice: for **IO-bound** work you no longer **pool**\nvirtual threads or agonize over pool sizing — you just create one per task.\nCaveats: **don't pool** them, avoid pinning (long `synchronized` blocks or native\ncalls keep the carrier blocked), and **platform-thread pools still matter for\nCPU-bound** work, where bounding parallelism to the core count is still right.\n",{"description":103},"Java executors and thread pool interview questions — the Executor framework, ExecutorService, ThreadPoolExecutor tuning, Callable and Future, CompletableFuture, and graceful shutdown.","java\u002Fconcurrency\u002Fexecutors-thread-pools","Executors & Thread Pools","cC2QXAGnVLuTnndEQtQ1cWXq-_dNO9YBs8R26jGFmiw",{"id":2219,"title":2220,"body":2221,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":2225,"navigation":108,"order":38,"path":2226,"questions":2227,"questionsCount":904,"related":250,"seo":2310,"seoDescription":2311,"stem":2312,"subtopic":2220,"topic":63,"topicSlug":65,"updated":809,"__hash__":2313},"qa\u002Fjava\u002Fexceptions\u002Fcustom-exceptions.md","Custom Exceptions",{"type":100,"value":2222,"toc":2223},[],{"title":103,"searchDepth":29,"depth":29,"links":2224},[],{},"\u002Fjava\u002Fexceptions\u002Fcustom-exceptions",[2228,2232,2236,2240,2244,2248,2251,2255,2259,2263,2267,2271,2275,2279,2283,2287,2291,2295,2299,2302,2306],{"id":2229,"difficulty":113,"q":2230,"a":2231},"why-custom-exceptions","Why would you create a custom exception instead of using a built-in one?","A custom exception gives an error a **domain-specific name and type** that\ncallers can catch precisely. `throw new RuntimeException(\"insufficient funds\")`\nforces callers to parse a string or catch everything; `throw new\nInsufficientFundsException(...)` lets them write `catch\n(InsufficientFundsException e)` and react to *that* failure alone.\n\n```java\n\u002F\u002F vague — caller can't distinguish this from any other RuntimeException\nthrow new RuntimeException(\"order not found: \" + id);\n\n\u002F\u002F expressive — a dedicated type the caller can target\nthrow new OrderNotFoundException(id);\n```\n\nCustom exceptions also let you **carry structured data** (the offending id, an\nerror code) and document the failure modes of your API in its type signature.\n**Rule of thumb:** create one when callers need to *react differently* to this\nerror or need data from it; otherwise reuse a built-in.\n",{"id":2233,"difficulty":105,"q":2234,"a":2235},"extend-which-class","Which class should a custom exception extend?","Extend **`Exception`** to make it **checked** (callers must catch or declare it)\nor **`RuntimeException`** to make it **unchecked** (no compiler obligation).\nNever extend `Throwable` or `Error` directly — those are reserved for the JVM and\ncatch-all framework code.\n\n```java\n\u002F\u002F checked: caller is forced to handle it\npublic class ConfigParseException extends Exception { }\n\n\u002F\u002F unchecked: a programming\u002Fusage error, no catch obligation\npublic class InvalidStateException extends RuntimeException { }\n```\n\nThe choice signals intent: subclass `Exception` for a recoverable condition the\ncaller should plan for, `RuntimeException` for a bug or precondition violation.\n**Rule of thumb:** pick the superclass first — it encodes whether the error is\n*expected* or a *defect*.\n",{"id":2237,"difficulty":105,"q":2238,"a":2239},"standard-constructors","What are the four standard constructors a custom exception should provide?","Mirror the four constructors that `Exception`\u002F`RuntimeException` themselves\nexpose, so callers can supply a message, a cause, or both:\n\n```java\npublic class PaymentException extends RuntimeException {\n  public PaymentException() { super(); }\n  public PaymentException(String message) { super(message); }\n  public PaymentException(String message, Throwable cause) {\n    super(message, cause);\n  }\n  public PaymentException(Throwable cause) { super(cause); }\n}\n```\n\nThe **`(String, Throwable)`** and **`(Throwable)`** constructors are the ones\npeople forget, yet they're the most important — they enable **exception\nchaining** (wrapping a lower-level cause). **Rule of thumb:** always include at\nleast the `(String message)` and `(String message, Throwable cause)` forms.\n",{"id":2241,"difficulty":126,"q":2242,"a":2243},"checked-vs-unchecked-design","How do you decide between a checked and an unchecked custom exception?","Make it **checked** when the error is a **recoverable, expected condition** the\ncaller can reasonably handle (a missing file, a failed network call). Make it\n**unchecked** when it represents a **programming error** or violated precondition\nthe caller can't sensibly recover from (`null` argument, illegal state).\n\n| Aspect | Checked (`extends Exception`) | Unchecked (`extends RuntimeException`) |\n| ------ | ----------------------------- | -------------------------------------- |\n| Compiler enforces handling | Yes | No |\n| Use for | Recoverable, anticipated | Bugs \u002F preconditions |\n| Method signature | Must declare with `throws` | No declaration needed |\n| Caller's typical action | Catch & recover\u002Fretry | Let it propagate, fix the bug |\n\n**Rule of thumb:** \"Can the caller do something useful about it?\" Yes -> checked\n(or at least catchable); no -> unchecked.\n",{"id":2245,"difficulty":126,"q":2246,"a":2247},"checked-exception-debate","What is the argument against checked exceptions?","Critics argue checked exceptions **hurt scalability and clutter code**: every\ncaller must catch or re-declare them, so adding a checked exception to a method\nripples `throws` clauses up the whole call stack. They also break cleanly with\n**lambdas and streams**, whose functional interfaces don't declare checked\nexceptions.\n\n```java\n\u002F\u002F a checked exception can't escape a stream lambda directly\nfiles.stream()\n     .map(f -> Files.readString(f)); \u002F\u002F won't compile — IOException is checked\n```\n\nThe result is often **swallowing or blanket-wrapping** in `RuntimeException`,\ndefeating the purpose. Modern frameworks (Spring, many libraries) lean almost\nentirely on **unchecked** exceptions for this reason. **Rule of thumb:** know\nboth sides — checked enforces handling, but overusing it leaks implementation and\nfights functional code.\n",{"id":468,"difficulty":105,"q":2249,"a":2250},"What is exception chaining and why does it matter?","Exception chaining is **wrapping a low-level exception inside a higher-level one\nwhile keeping the original as the \"cause.\"** It lets you raise a meaningful\ndomain exception without **throwing away the root-cause diagnostic information**.\n\n```java\ntry {\n  return jdbc.query(sql);\n} catch (SQLException e) {\n  \u002F\u002F wrap, but keep the SQLException as the cause\n  throw new RepositoryException(\"failed to load user \" + id, e);\n}\n```\n\nThe chained cause appears in the stack trace under **\"Caused by:\"**, so you see\nboth the abstract failure and the SQL error that triggered it. Losing the cause\nmeans losing the line that actually broke. **Rule of thumb:** when translating an\nexception, always pass the original in as the cause.\n",{"id":2252,"difficulty":105,"q":2253,"a":2254},"initcause-vs-constructor","What is the difference between the cause constructor and initCause()?","Both record a **cause**; the constructor is the preferred, concise form, while\n`initCause()` exists for exceptions whose class predates the cause constructors or\ndoesn't expose one.\n\n```java\n\u002F\u002F preferred — set the cause at construction\nthrow new ServiceException(\"lookup failed\", sqlEx);\n\n\u002F\u002F fallback — when no cause constructor is available\nServiceException ex = new ServiceException(\"lookup failed\");\nex.initCause(sqlEx);   \u002F\u002F can be called only ONCE\nthrow ex;\n```\n\n`initCause()` may be called **exactly once** and only if the cause wasn't already\nset, otherwise it throws `IllegalStateException`. `getCause()` reads it back.\n**Rule of thumb:** use the `(message, cause)` constructor; reach for `initCause`\nonly when a constructor isn't an option.\n",{"id":2256,"difficulty":113,"q":2257,"a":2258},"getcause","What does getCause() return and when is it useful?","`Throwable.getCause()` returns the **underlying exception** that was chained in,\nor `null` if none was set. It lets handlers and logging code **walk the chain**\nto find the root cause.\n\n```java\ntry {\n  service.process();\n} catch (ServiceException e) {\n  Throwable root = e;\n  while (root.getCause() != null) root = root.getCause();\n  log.error(\"root cause: {}\", root.getMessage());\n}\n```\n\nMost logging frameworks print the full chain automatically (the \"Caused by:\"\nlines), so you rarely walk it by hand — but `getCause()` is how you inspect it\nprogrammatically (e.g., to unwrap a known wrapped exception). **Rule of thumb:**\nuse `getCause()` to inspect or unwrap; let the logger print the chain.\n",{"id":2260,"difficulty":126,"q":2261,"a":2262},"preserve-stack-trace","How can you accidentally lose a stack trace, and how do you preserve it?","You lose the original trace by **catching an exception and throwing a new one\nwithout passing the cause** — the new exception's trace starts at the `throw`\nsite, hiding where it really failed.\n\n```java\n\u002F\u002F BAD — the original cause and its line are gone\ncatch (SQLException e) {\n  throw new DaoException(\"query failed\");\n}\n\n\u002F\u002F GOOD — chain the cause; both traces are kept\ncatch (SQLException e) {\n  throw new DaoException(\"query failed\", e);\n}\n```\n\nEqually bad is **swallowing** (`catch (Exception e) {}`) or logging *and*\nrethrowing a fresh exception, which double-logs and detaches the trace. **Rule of\nthumb:** when you rethrow, always carry the cause; never create a new exception\nthat drops the original.\n",{"id":2264,"difficulty":105,"q":2265,"a":2266},"dont-swallow","What does it mean to swallow an exception and why is it dangerous?","Swallowing is **catching an exception and doing nothing** (or just logging at a\nlow level) so the failure silently disappears. The program continues in a broken\nstate and the bug surfaces far away, with no trace of the origin.\n\n```java\n\u002F\u002F the worst line in any codebase\ntry {\n  risky();\n} catch (Exception e) {\n  \u002F\u002F empty — failure vanishes\n}\n```\n\nIf you genuinely must ignore an exception, **comment why** and at minimum log it\nwith the stack trace. Catching `Exception`\u002F`Throwable` broadly is itself a smell —\nit can hide `RuntimeException`s and even `Error`s you never meant to suppress.\n**Rule of thumb:** never leave a `catch` block empty; handle, rethrow, or log\nwith the cause.\n",{"id":2268,"difficulty":105,"q":2269,"a":2270},"custom-fields","How do you add custom data to an exception?","Add **final fields** populated through the constructor and exposed via getters.\nThis lets handlers retrieve structured context (an id, an error code) instead of\nparsing the message string.\n\n```java\npublic class OrderNotFoundException extends RuntimeException {\n  private final long orderId;\n\n  public OrderNotFoundException(long orderId) {\n    super(\"order not found: \" + orderId);\n    this.orderId = orderId;\n  }\n  public long getOrderId() { return orderId; }\n}\n```\n\nNow a caller can do `catch (OrderNotFoundException e) { retry(e.getOrderId()); }`.\nKeep the fields **immutable** (`final`) since an exception is a one-shot value\nobject. **Rule of thumb:** put any data the handler might need into typed fields,\nnot just the message.\n",{"id":2272,"difficulty":113,"q":2273,"a":2274},"naming-convention","What is the naming convention for exception classes?","The class name should **end with `Exception`** and describe the failure clearly,\ne.g. `InsufficientFundsException`, `OrderNotFoundException`, `ConfigParseException`.\nSubtypes of `Error` end with `Error`.\n\n```java\nclass InvalidTokenException extends RuntimeException { } \u002F\u002F good\nclass TokenProblem extends RuntimeException { }          \u002F\u002F unclear — avoid\n```\n\nThe convention makes exceptions instantly recognizable in code and stack traces,\nand mirrors the JDK's own (`IllegalArgumentException`, `IOException`). Name them\nfor the **problem**, not the throwing method. **Rule of thumb:** suffix with\n`Exception` and name the condition, not the location.\n",{"id":2276,"difficulty":105,"q":2277,"a":2278},"serializable","Why should a custom exception be serializable and how?","`Throwable` already **implements `Serializable`**, so every exception is\nserializable by inheritance — important because exceptions cross JVM boundaries\n(RMI, distributed apps, app servers). To keep serialization stable you should\ndeclare a **`serialVersionUID`** and ensure any custom fields are themselves\nserializable.\n\n```java\npublic class RemoteCallException extends RuntimeException {\n  private static final long serialVersionUID = 1L;\n  private final String endpoint;   \u002F\u002F String is serializable — OK\n\n  public RemoteCallException(String endpoint, Throwable cause) {\n    super(\"call failed: \" + endpoint, cause);\n    this.endpoint = endpoint;\n  }\n}\n```\n\nWithout an explicit `serialVersionUID`, the compiler-generated one changes with\nany edit, breaking deserialization of older instances. **Rule of thumb:** add a\n`serialVersionUID` and keep custom fields serializable (or mark them `transient`).\n",{"id":2280,"difficulty":105,"q":2281,"a":2282},"immutable-exceptions","Should custom exceptions be immutable?","Yes — treat an exception as an **immutable value object**. Set everything through\nthe constructor and make fields `final`; an exception describes a moment in time\nand shouldn't be mutated after it's thrown.\n\n```java\npublic class ValidationException extends RuntimeException {\n  private final List\u003CString> errors;\n\n  public ValidationException(List\u003CString> errors) {\n    super(errors.size() + \" validation error(s)\");\n    this.errors = List.copyOf(errors);   \u002F\u002F defensive, unmodifiable copy\n  }\n  public List\u003CString> getErrors() { return errors; }\n}\n```\n\nDefensively copy mutable inputs (here `List.copyOf`) so the stored data can't be\nchanged by the caller afterward. Immutability also makes exceptions safe to share\nacross threads. **Rule of thumb:** all-`final` fields, defensive copies, no\nsetters.\n",{"id":2284,"difficulty":105,"q":2285,"a":2286},"dont-extend-throwable","Why should you not extend Throwable or Error directly?","`Throwable` is the root of *everything* thrown; extending it directly creates a\ntype that is neither a clean `Exception` nor an `Error`, confusing callers and\ncatch blocks. `Error` is reserved for **serious JVM-level failures** (e.g.\n`OutOfMemoryError`) that applications are **not meant to catch**.\n\n```java\nclass MyFailure extends Error { }   \u002F\u002F WRONG — implies an unrecoverable JVM error\n\nclass MyFailure extends RuntimeException { }  \u002F\u002F right level of abstraction\n```\n\nThrowing an `Error` subtype tricks catch-all `catch (Exception e)` handlers into\n*not* catching it, and signals \"the JVM is broken\" when it isn't. **Rule of\nthumb:** subclass `Exception` or `RuntimeException` — leave `Throwable` and\n`Error` to the platform.\n",{"id":2288,"difficulty":105,"q":2289,"a":2290},"dont-overuse","When is creating a custom exception overkill?","When a **standard JDK exception already says exactly what's wrong**, reuse it\nrather than inventing a parallel type. A bad argument is\n`IllegalArgumentException`; a bad object state is `IllegalStateException`; a\n`null` you reject is `NullPointerException` (or `Objects.requireNonNull`).\n\n```java\n\u002F\u002F no need for a custom \"BadAgeException\"\nif (age \u003C 0) throw new IllegalArgumentException(\"age must be >= 0\");\n\nObjects.requireNonNull(name, \"name\");  \u002F\u002F throws NPE with a clear message\n```\n\nA codebase littered with one-off exception classes that nobody catches\nspecifically is just noise. **Rule of thumb:** create a custom exception only\nwhen callers will *catch it by type* or need *data from it*; otherwise reuse a\nbuilt-in.\n",{"id":2292,"difficulty":105,"q":2293,"a":2294},"throwing-in-constructor","Can you throw an exception from a constructor, and what are the implications?","Yes — throwing from a constructor is the correct way to **reject invalid\nconstruction** so no half-initialized object escapes. If the constructor throws,\nthe object is **never assigned** to the variable and becomes garbage.\n\n```java\npublic class Percentage {\n  private final int value;\n  public Percentage(int value) {\n    if (value \u003C 0 || value > 100)\n      throw new IllegalArgumentException(\"0..100, got \" + value);\n    this.value = value;   \u002F\u002F only reached if valid\n  }\n}\n```\n\nValidate **before** assigning fields, and prefer **unchecked** exceptions here\nsince invalid arguments are programming errors. Beware throwing from a constructor\nthat already opened resources — the object's `close()` won't be called, so clean\nup first. **Rule of thumb:** fail fast in the constructor to enforce invariants.\n",{"id":2296,"difficulty":105,"q":2297,"a":2298},"rethrowing","What does it mean to rethrow an exception?","Rethrowing is **catching an exception, doing some work (log, clean up, add\ncontext), then throwing it onward** so an outer handler still sees it. You can\nrethrow the same instance or wrap it.\n\n```java\ntry {\n  process(record);\n} catch (ServiceException e) {\n  metrics.increment(\"process.failure\");\n  throw e;            \u002F\u002F rethrow the SAME exception, trace intact\n}\n```\n\nRethrowing the **same** instance preserves the original stack trace perfectly.\nSince Java 7, **precise rethrow** lets the compiler narrow what a rethrown\n`Exception` can actually be, so you can declare specific subtypes in `throws`.\n**Rule of thumb:** rethrow the same object to keep the trace; wrap only when you\nneed to change the abstraction level.\n",{"id":520,"difficulty":126,"q":2300,"a":2301},"What is exception translation and why is it a best practice?","Exception translation is **catching a low-level exception and throwing a\nhigher-level one appropriate to your API's abstraction** — so callers depend on\n*your* exception types, not on implementation details like `SQLException` or\n`IOException`.\n\n```java\n\u002F\u002F the repository hides JDBC behind its own abstraction\npublic User findById(long id) {\n  try {\n    return jdbc.queryForObject(SQL, mapper, id);\n  } catch (SQLException e) {\n    throw new UserRepositoryException(\"findById \" + id, e); \u002F\u002F translate + chain\n  }\n}\n```\n\nThis keeps callers decoupled from the data layer; you could swap JDBC for an ORM\nwithout changing the exceptions they catch. Always **chain the cause** so the\nlow-level detail is still available for debugging. **Rule of thumb:** translate\nat layer boundaries, and never let leaky low-level exceptions cross your API.\n",{"id":2303,"difficulty":105,"q":2304,"a":2305},"business-vs-technical","What is the difference between business and technical exceptions?","A **business (domain) exception** represents a violation of business rules that\nthe application expects and often handles (`InsufficientFundsException`,\n`DuplicateEmailException`). A **technical (system) exception** represents\ninfrastructure failure (`DatabaseUnavailableException`, network timeouts) that's\nusually unexpected and bubbles up to generic handling.\n\n```java\n\u002F\u002F business: expected, often caught and shown to the user\nthrow new InsufficientFundsException(accountId, amount);\n\n\u002F\u002F technical: infrastructure broke — log, alert, return 500\nthrow new ServiceUnavailableException(\"payment gateway down\", cause);\n```\n\nSeparating them lets you handle each differently: business errors map to friendly\nuser messages and 4xx responses, technical ones to retries, alerts, and 5xx.\n**Rule of thumb:** model business failures as their own hierarchy, distinct from\ntechnical\u002Finfrastructure failures.\n",{"id":2307,"difficulty":126,"q":2308,"a":2309},"unchecked-default-style","Why do many modern Java codebases default to unchecked exceptions?","Modern style (popularized by Spring and much of the ecosystem) favors\n**unchecked exceptions** because they keep method signatures clean, **work with\nlambdas and streams**, and avoid forcing every caller to catch or re-declare.\nHandling is centralized instead of scattered.\n\n```java\n\u002F\u002F a single global handler turns domain exceptions into HTTP responses\n@ExceptionHandler(OrderNotFoundException.class)\npublic ResponseEntity\u003C?> handle(OrderNotFoundException e) {\n  return ResponseEntity.status(404).body(e.getMessage());\n}\n```\n\nThe trade-off is the compiler no longer reminds callers an error can occur, so\nteams rely on **documentation (`@throws` Javadoc) and convention** instead. Some\nargue this loses checked exceptions' safety, but most accept it for the reduced\nceremony. **Rule of thumb:** default to unchecked domain exceptions and handle\nthem centrally, documenting them clearly.\n",{"description":103},"Java custom exceptions interview questions — when and how to create your own exception classes, checked vs unchecked design, exception chaining, preserving stack traces, and best practices.","java\u002Fexceptions\u002Fcustom-exceptions","2aLetMEoLmBtyD9OBd0Ho317zD_7ntF_i_n55yrfnNg",{"id":2315,"title":2316,"body":2317,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":2321,"navigation":108,"order":38,"path":2322,"questions":2323,"questionsCount":1370,"related":250,"seo":2419,"seoDescription":2420,"stem":2421,"subtopic":2316,"topic":20,"topicSlug":21,"updated":809,"__hash__":2422},"qa\u002Fjava\u002Ffundamentals\u002Farrays.md","Arrays",{"type":100,"value":2318,"toc":2319},[],{"title":103,"searchDepth":29,"depth":29,"links":2320},[],{},"\u002Fjava\u002Ffundamentals\u002Farrays",[2324,2328,2332,2335,2339,2343,2347,2351,2355,2359,2363,2367,2371,2375,2379,2383,2387,2391,2395,2399,2403,2407,2411,2415],{"id":2325,"difficulty":113,"q":2326,"a":2327},"declare-initialize","What are the ways to declare and initialize an array in Java?","An array is declared with `type[]` and created with `new`, an **array\ninitializer** `{ ... }`, or both. The brackets can sit on the type or the\nvariable, but `type[]` is the convention.\n\n```java\nint[] a = new int[3];          \u002F\u002F size only — defaults {0,0,0}\nint[] b = new int[]{1, 2, 3};  \u002F\u002F size + values\nint[] c = {1, 2, 3};           \u002F\u002F shorthand initializer (declaration only)\nint d[] = {1, 2, 3};           \u002F\u002F legal but discouraged (C-style)\n```\n\nThe bare `{ ... }` shorthand works **only at declaration** — you can't write\n`c = {4,5,6};` later; you'd need `c = new int[]{4,5,6};`. Either form fixes the\nlength at creation.\n",{"id":2329,"difficulty":113,"q":2330,"a":2331},"array-is-object","Is an array a primitive or an object in Java?","An array is always an **object** on the heap, even an array of primitives. The\nvariable holds a **reference** to it, the array has a runtime class\n(`int[].class`), and it inherits from `Object` — so you can call\n`clone()`, read `.length`, and store it in an `Object` variable.\n\n```java\nint[] a = {1, 2, 3};\nObject o = a;                  \u002F\u002F arrays are Objects\nSystem.out.println(a.getClass().getName()); \u002F\u002F \"[I\" — int array\nint[] copy = a.clone();        \u002F\u002F inherited (overridden) clone\n```\n\nBecause it's an object, an array variable can be `null`, and elements of a\nprimitive array are stored **inline** (contiguously) while elements of an object\narray are **references**.\n",{"id":607,"difficulty":113,"q":2333,"a":2334},"What are the default values of array elements?","Allocating an array with `new` **zero-initializes** every element — you never get\ngarbage. The default depends on the element type:\n\n| Element type | Default |\n| ------------ | ------- |\n| numeric (`int`, `double`, …) | `0` \u002F `0.0` |\n| `boolean` | `false` |\n| `char` | `'\u0000'` (null char) |\n| reference (`String`, objects) | `null` |\n\n```java\nint[] nums = new int[3];        \u002F\u002F {0, 0, 0}\nboolean[] flags = new boolean[2]; \u002F\u002F {false, false}\nString[] names = new String[2]; \u002F\u002F {null, null}\n```\n\nThis differs from **local variables**, which get no default and must be assigned\nbefore use. Array slots, like fields, are always initialized.\n",{"id":2336,"difficulty":113,"q":2337,"a":2338},"length-fixed","Can you change the size of an array after creation?","No. An array's **length is fixed at creation** and can never change. To \"grow\"\none you allocate a **new, larger array** and copy the elements over (which is\nexactly what `ArrayList` does internally).\n\n```java\nint[] a = {1, 2, 3};\n\u002F\u002F a = a + one element  -> not possible\nint[] bigger = Arrays.copyOf(a, a.length + 1); \u002F\u002F new array, last slot = 0\nbigger[3] = 4;          \u002F\u002F {1, 2, 3, 4}\n```\n\nIf you need a resizable, append-friendly structure, reach for `ArrayList`\ninstead of hand-rolling array growth.\n",{"id":2340,"difficulty":113,"q":2341,"a":2342},"length-field","What is the difference between length, length() and size()?","Three different things that beginners confuse:\n\n- **`array.length`** — a **field** (no parentheses) giving an array's size.\n- **`string.length()`** — a **method** giving a `String`'s character count.\n- **`collection.size()`** — a **method** on `List`\u002F`Set`\u002F`Map` giving its element count.\n\n```java\nint[] a = {1, 2, 3};\nString s = \"hello\";\nList\u003CInteger> list = List.of(1, 2);\n\na.length     \u002F\u002F 3  — field, no ()\ns.length()   \u002F\u002F 5  — method\nlist.size()  \u002F\u002F 2  — method\n```\n\nWriting `a.length()` or `s.length` is a compile error — memorize which is which.\n",{"id":2344,"difficulty":113,"q":2345,"a":2346},"index-out-of-bounds","What happens when you access an index outside an array's bounds?","Java performs **bounds checking** on every access. A valid index is `0` to\n`length - 1`; anything else throws **`ArrayIndexOutOfBoundsException`** at\nruntime (it's unchecked, so it isn't caught at compile time).\n\n```java\nint[] a = {10, 20, 30};\na[0];    \u002F\u002F 10 — first element\na[2];    \u002F\u002F 30 — last (length - 1)\na[3];    \u002F\u002F ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3\na[-1];   \u002F\u002F also AIOOBE — no negative indexing in Java\n```\n\nUnlike some languages, Java has **no negative indexing**; `a[-1]` is an error,\nnot \"last element\". Bounds checks are what make Java memory-safe here.\n",{"id":2348,"difficulty":105,"q":2349,"a":2350},"negative-size","What happens if you create an array with a negative size?","The size is evaluated at runtime, and a **negative** length throws\n**`NegativeArraySizeException`**. A size of `0` is perfectly legal — it gives a\nvalid, empty array.\n\n```java\nint[] ok    = new int[0];   \u002F\u002F legal — empty array, length 0\nint n = -1;\nint[] bad   = new int[n];   \u002F\u002F NegativeArraySizeException at runtime\n```\n\nThis catches interviewees who assume any compile-passing `new int[expr]` is\nsafe — a computed negative size blows up only when the line executes.\n",{"id":2352,"difficulty":105,"q":2353,"a":2354},"multidimensional","How do multidimensional arrays work in Java?","Java has no true 2D arrays — `int[][]` is an **array of arrays**. The outer array\nholds references to inner arrays, each a separate heap object.\n\n```java\nint[][] grid = new int[2][3];  \u002F\u002F 2 rows, each an int[3]\ngrid[0][1] = 5;\ngrid.length      \u002F\u002F 2 — number of rows\ngrid[0].length   \u002F\u002F 3 — columns in row 0\n\nfor (int[] row : grid)         \u002F\u002F each row is itself an int[]\n  for (int v : row) { \u002F* ... *\u002F }\n```\n\nBecause the inner arrays are independent objects, accessing `grid[i][j]` is two\npointer hops. You can also declare more dimensions (`int[][][]`) the same way.\n",{"id":2356,"difficulty":105,"q":2357,"a":2358},"jagged-arrays","What is a jagged (ragged) array?","A **jagged** array is a multidimensional array whose inner rows have **different\nlengths**. Since each row is a separate array object, this is fully legal — you\njust allocate the rows yourself.\n\n```java\nint[][] jagged = new int[3][];   \u002F\u002F 3 rows, none allocated yet\njagged[0] = new int[]{1};        \u002F\u002F length 1\njagged[1] = new int[]{2, 3};     \u002F\u002F length 2\njagged[2] = new int[]{4, 5, 6};  \u002F\u002F length 3\n\nfor (int[] row : jagged)\n  System.out.println(row.length); \u002F\u002F 1, 2, 3\n```\n\nAlways iterate with `row.length` rather than a fixed column count, since rows\ncan differ — and an unallocated row stays `null` until you assign it.\n",{"id":2360,"difficulty":105,"q":2361,"a":2362},"array-of-objects","How does an array of objects differ from an array of primitives?","A primitive array stores the **values inline**; an object array stores\n**references**, and creating it does **not** create the objects — every slot\nstarts as `null`.\n\n```java\nint[] nums = new int[2];        \u002F\u002F {0, 0} — values ready to use\nString[] names = new String[2]; \u002F\u002F {null, null} — no String objects yet\n\nnames[0].length();              \u002F\u002F NullPointerException — slot is null!\nnames[0] = \"Ada\";               \u002F\u002F must populate first\nnames[0].length();              \u002F\u002F now 3\n```\n\nThe classic bug: iterating an object array and calling methods before filling it,\nwhich throws `NullPointerException`. Primitive arrays never have this problem.\n",{"id":2364,"difficulty":126,"q":2365,"a":2366},"array-covariance","What is array covariance in Java?","Java arrays are **covariant**: if `Sub` extends `Super`, then `Sub[]` is a\nsubtype of `Super[]`. So you can assign a `String[]` to an `Object[]` variable.\nThis is convenient but **not type-safe** at compile time.\n\n```java\nObject[] arr = new String[3];   \u002F\u002F legal — covariance\narr[0] = \"ok\";                  \u002F\u002F fine, it's really a String[]\narr[1] = 42;                    \u002F\u002F compiles, but throws at runtime\n```\n\nContrast with **generics**, which are *invariant* — `List\u003CString>` is **not** a\n`List\u003CObject>`. Generics chose compile-time safety; arrays chose flexibility,\npushing the check to runtime (see `ArrayStoreException`).\n",{"id":2368,"difficulty":126,"q":2369,"a":2370},"array-store-exception","When does ArrayStoreException occur?","Because arrays are covariant, the JVM must check at **runtime** that every value\nyou store is compatible with the array's **actual** element type. Storing an\nincompatible type throws **`ArrayStoreException`**.\n\n```java\nObject[] arr = new String[2];   \u002F\u002F actual type is String[]\narr[0] = \"hi\";                  \u002F\u002F OK\narr[0] = Integer.valueOf(42);   \u002F\u002F ArrayStoreException at runtime\n```\n\nThis runtime store check is the price of covariance, and it's why generics were\ndesigned to be invariant — the compiler can guarantee type safety for\n`List\u003CString>`, so no equivalent check is needed.\n",{"id":2372,"difficulty":105,"q":2373,"a":2374},"arrays-sort","How do you sort an array, including with a Comparator?","`Arrays.sort` sorts **in place**. Primitive arrays use a tuned dual-pivot\nquicksort; object arrays use a stable merge sort and can take a `Comparator`.\n\n```java\nint[] nums = {3, 1, 2};\nArrays.sort(nums);                  \u002F\u002F {1, 2, 3} — natural order\n\nString[] words = {\"banana\", \"apple\"};\nArrays.sort(words);                 \u002F\u002F natural (lexicographic)\nArrays.sort(words, Comparator.reverseOrder()); \u002F\u002F {\"banana\", \"apple\"}\nArrays.sort(words, Comparator.comparingInt(String::length)); \u002F\u002F by length\n\nArrays.sort(nums, 0, 2);            \u002F\u002F sort only a sub-range [0,2)\n```\n\nNote primitive arrays **can't** take a `Comparator` (no objects to compare) — box\nto `Integer[]` if you need custom ordering of numbers.\n",{"id":2376,"difficulty":105,"q":2377,"a":2378},"parallel-sort","What is Arrays.parallelSort and when would you use it?","`Arrays.parallelSort` (Java 8+) sorts large arrays using a **parallel\nmerge-sort** across the common ForkJoinPool, then merges the pieces. Same result\nas `Arrays.sort`, faster on big arrays and multiple cores.\n\n```java\nint[] big = new int[10_000_000];\n\u002F\u002F ... fill big ...\nArrays.parallelSort(big);    \u002F\u002F multi-threaded sort\n```\n\nIt only pays off above a size threshold (roughly a few thousand elements);\nbelow that it falls back to a sequential sort, so for small arrays plain\n`Arrays.sort` is simpler and just as fast.\n",{"id":2380,"difficulty":105,"q":2381,"a":2382},"binary-search","How does Arrays.binarySearch work and what is the catch?","`Arrays.binarySearch` does an O(log n) search but **requires the array to be\nsorted first** — on unsorted input the result is undefined. If found it returns\nthe index; if not, it returns a **negative** value: `-(insertionPoint) - 1`.\n\n```java\nint[] a = {10, 20, 30, 40};\nArrays.binarySearch(a, 30);   \u002F\u002F 2  — found at index 2\nArrays.binarySearch(a, 25);   \u002F\u002F -3 — would insert at index 2: -(2)-1\n```\n\nDecode a miss with `int insertAt = -result - 1;`. Forgetting to sort first is the\nmost common bug — `binarySearch` silently returns garbage on unsorted data.\n",{"id":2384,"difficulty":113,"q":2385,"a":2386},"fill-equals-tostring","What do Arrays.fill, Arrays.equals and Arrays.toString do?","Three everyday `Arrays` helpers:\n\n- **`fill`** — sets every element (or a range) to one value.\n- **`equals`** — element-by-element value comparison (`==` on arrays only checks references).\n- **`toString`** — a readable `\"[1, 2, 3]\"` (an array's own `toString` prints `[I@1b6d3586`).\n\n```java\nint[] a = new int[3];\nArrays.fill(a, 7);              \u002F\u002F {7, 7, 7}\n\nint[] b = {7, 7, 7};\na == b              \u002F\u002F false — different objects\nArrays.equals(a, b) \u002F\u002F true  — same contents\n\nSystem.out.println(a);                 \u002F\u002F [I@... (unhelpful)\nSystem.out.println(Arrays.toString(a)); \u002F\u002F [7, 7, 7]\n```\n\nAlways use `Arrays.equals`\u002F`Arrays.toString` — the inherited `Object` versions\ncompare references and print the type+hash.\n",{"id":2388,"difficulty":105,"q":2389,"a":2390},"deep-equals-tostring","What is the difference between equals\u002FdeepEquals and toString\u002FdeepToString?","The plain `Arrays.equals` and `Arrays.toString` are **shallow** — for a 2D array\nthey compare\u002Fprint the inner arrays by reference, which is wrong. The\n**`deep`** variants recurse into nested arrays.\n\n```java\nint[][] a = {{1, 2}, {3, 4}};\nint[][] b = {{1, 2}, {3, 4}};\n\nArrays.equals(a, b)      \u002F\u002F false — compares inner int[] references\nArrays.deepEquals(a, b)  \u002F\u002F true  — recurses into rows\n\nArrays.toString(a)       \u002F\u002F [[I@..., [I@...]\nArrays.deepToString(a)   \u002F\u002F [[1, 2], [3, 4]]\n```\n\nRule: use `deepEquals`\u002F`deepToString` for **multidimensional or nested** arrays,\nthe shallow ones for flat arrays.\n",{"id":2392,"difficulty":105,"q":2393,"a":2394},"copyof-copyofrange","How do Arrays.copyOf and Arrays.copyOfRange work?","Both return a **new** array. `copyOf` copies from the start to a given length\n(truncating or **zero-padding** if longer); `copyOfRange` copies a `[from, to)`\nslice.\n\n```java\nint[] a = {1, 2, 3};\nArrays.copyOf(a, 2);          \u002F\u002F {1, 2}        — truncated\nArrays.copyOf(a, 5);          \u002F\u002F {1, 2, 3, 0, 0} — padded with defaults\nArrays.copyOfRange(a, 1, 3);  \u002F\u002F {2, 3}        — indices 1..2 (to is exclusive)\n```\n\n`copyOf(a, a.length + n)` is the standard idiom for \"grow this array\". Both are\n**shallow** copies for object arrays (they copy references, not the objects).\n",{"id":2396,"difficulty":105,"q":2397,"a":2398},"system-arraycopy","What is System.arraycopy and how is it different from copyOf?","`System.arraycopy` is a **native, low-level** bulk copy into an **existing**\ndestination array: `arraycopy(src, srcPos, dest, destPos, length)`. It's the\nfastest copy and what `copyOf`\u002F`ArrayList` use under the hood — but you must\nallocate the destination yourself.\n\n```java\nint[] src = {1, 2, 3, 4, 5};\nint[] dest = new int[5];\nSystem.arraycopy(src, 1, dest, 0, 3); \u002F\u002F dest = {2, 3, 4, 0, 0}\n```\n\nUse `System.arraycopy` when copying into an array you already have (or inserting\na range); use `Arrays.copyOf` when you just want a fresh copy and let it do the\nallocation.\n",{"id":2400,"difficulty":126,"q":2401,"a":2402},"clone-shallow","Is array clone() a deep or shallow copy?","`clone()` makes a **shallow** copy: a new array of the same length with the same\nelements. For a primitive array that's effectively a deep copy. For an object (or\n2D) array, the **references are copied** — both arrays point at the same objects.\n\n```java\nint[] a = {1, 2, 3};\nint[] b = a.clone();\nb[0] = 99;            \u002F\u002F a unchanged — independent (primitives)\n\nint[][] grid = {{1, 2}, {3, 4}};\nint[][] copy = grid.clone();\ncopy[0][0] = 99;      \u002F\u002F grid[0][0] is ALSO 99 — shared inner array!\n```\n\nTo truly deep-copy a 2D array, clone each row yourself:\n`for (int i = 0; i \u003C grid.length; i++) copy[i] = grid[i].clone();`.\n",{"id":2404,"difficulty":126,"q":2405,"a":2406},"aslist-gotcha","What is the gotcha with Arrays.asList?","`Arrays.asList` returns a **fixed-size** `List` **backed by the array** — it's a\n*view*, not a normal `ArrayList`. You can read and `set`, but `add`\u002F`remove`\nthrow `UnsupportedOperationException`, and changes write through to the array.\n\n```java\nInteger[] arr = {1, 2, 3};\nList\u003CInteger> list = Arrays.asList(arr);\nlist.set(0, 99);     \u002F\u002F OK — also changes arr[0] to 99\nlist.add(4);         \u002F\u002F UnsupportedOperationException — fixed size\n\n\u002F\u002F also: passing an int[] gives a List\u003Cint[]> of size 1, not List\u003CInteger>!\nList\u003CInteger> wrong = Arrays.asList(1, 2, 3); \u002F\u002F OK with varargs of Integer\n\n\u002F\u002F for a real mutable list:\nList\u003CInteger> real = new ArrayList\u003C>(Arrays.asList(arr));\n```\n\nTwo traps: it's **not resizable**, and `Arrays.asList(intArray)` boxes the\n*array itself* (a one-element `List\u003Cint[]>`) — use an `Integer[]` or a stream.\n",{"id":2408,"difficulty":105,"q":2409,"a":2410},"array-to-stream","How do you convert between an array, a List and a Stream?","The standard bridges:\n\n```java\nint[] prims = {1, 2, 3};\nIntStream is = Arrays.stream(prims);     \u002F\u002F primitive array -> IntStream\nint[] back  = is.map(x -> x * 2).toArray();\n\nString[] arr = {\"a\", \"b\"};\nList\u003CString> list = new ArrayList\u003C>(Arrays.asList(arr)); \u002F\u002F array -> List\nString[] arr2 = list.toArray(new String[0]);            \u002F\u002F List -> array\n\nStream\u003CString> s = Arrays.stream(arr);   \u002F\u002F object array -> Stream\nString[] arr3 = s.toArray(String[]::new);\n```\n\nNote `Arrays.stream(int[])` gives an `IntStream` (no boxing), whereas\n`Stream.of(int[])` would give a `Stream\u003Cint[]>` of one element — prefer\n`Arrays.stream` for primitive arrays.\n",{"id":2412,"difficulty":105,"q":2413,"a":2414},"varargs-arrays","How are varargs related to arrays?","A varargs parameter (`Type... args`) **is an array** — the compiler packages the\npassed arguments into a `Type[]`. Inside the method `args` is a normal array with\n`.length` and indexing.\n\n```java\nstatic int sum(int... nums) {     \u002F\u002F nums is really an int[]\n  int total = 0;\n  for (int n : nums) total += n;  \u002F\u002F iterate like any array\n  return total;\n}\nsum(1, 2, 3);          \u002F\u002F compiler builds new int[]{1, 2, 3}\nsum(new int[]{1, 2});  \u002F\u002F can also pass an array directly\nsum();                 \u002F\u002F empty array, length 0 (not null)\n```\n\nBecause it's just an array, varargs must be the **last** parameter, and passing\nan existing array works directly. An empty call yields a zero-length array, not\n`null`.\n",{"id":2416,"difficulty":105,"q":2417,"a":2418},"array-vs-arraylist","What is the difference between an array and an ArrayList?","| Aspect | Array | `ArrayList` |\n| ------ | ----- | ----------- |\n| Size | **fixed** at creation | **dynamic** (grows\u002Fshrinks) |\n| Element type | primitives **or** objects | objects only (boxes primitives) |\n| Access | `a[i]`, field `.length` | `get(i)`\u002F`set`, method `.size()` |\n| Type safety | covariant (runtime check) | generic, invariant (compile-time) |\n| Performance | no boxing, less overhead | boxing + resize cost |\n\n```java\nint[] arr = new int[3];          \u002F\u002F fixed, primitive, fast\nList\u003CInteger> list = new ArrayList\u003C>(); \u002F\u002F resizable, boxes ints\nlist.add(1); list.add(2);        \u002F\u002F grows automatically\n```\n\nChoose an **array** for fixed-size, primitive-heavy, performance-critical code;\nchoose **`ArrayList`** when the size varies or you want the rich `List` API.\n`ArrayList` is itself backed by a resizing array.\n",{"description":103},"Java arrays interview questions — declaration and initialization, default values, multidimensional and jagged arrays, array covariance, Arrays utility methods, copying, and array vs ArrayList.","java\u002Ffundamentals\u002Farrays","0j6qqsSf8ktXBDepdiNsvEtmK97n9_F-BthkA5x8Low",{"id":2424,"title":2425,"body":2426,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":2430,"navigation":108,"order":38,"path":2431,"questions":2432,"questionsCount":904,"related":250,"seo":2515,"seoDescription":2516,"stem":2517,"subtopic":2425,"topic":37,"topicSlug":39,"updated":809,"__hash__":2518},"qa\u002Fjava\u002Fgenerics\u002Ftype-erasure.md","Type Erasure",{"type":100,"value":2427,"toc":2428},[],{"title":103,"searchDepth":29,"depth":29,"links":2429},[],{},"\u002Fjava\u002Fgenerics\u002Ftype-erasure",[2433,2437,2441,2445,2449,2453,2457,2460,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511],{"id":2434,"difficulty":105,"q":2435,"a":2436},"what-is-type-erasure","What is type erasure in Java generics?","**Type erasure** is the process by which the compiler **removes all generic\ntype information** during compilation. Generics exist only at **compile time**\nfor type checking; at runtime the type parameters are gone, so a\n`List\u003CString>` and a `List\u003CInteger>` are both just plain `List`.\n\n```java\nList\u003CString> a = new ArrayList\u003C>();\nList\u003CInteger> b = new ArrayList\u003C>();\nSystem.out.println(a.getClass() == b.getClass()); \u002F\u002F true — both ArrayList\n```\n\nThe compiler replaces type parameters with their **bound** (or `Object` if\nunbounded) and inserts casts where needed. The result is bytecode that looks\nessentially like pre-generics Java. **Rule of thumb:** generics are a\ncompile-time fiction — nothing about the type argument survives to runtime.\n",{"id":2438,"difficulty":105,"q":2439,"a":2440},"why-type-erasure","Why did Java implement generics using type erasure?","The driving reason was **backward compatibility**. Generics arrived in Java 5,\nlong after millions of lines of pre-generics code existed. Erasure let\ngeneric code and legacy raw-type code **interoperate** on the same JVM without\nchanging the bytecode format or breaking existing libraries.\n\n```java\nList\u003CString> generic = new ArrayList\u003C>();\nList raw = generic;          \u002F\u002F legacy raw type — still works\nraw.add(\"ok\");               \u002F\u002F unchecked, but compiles and runs\n```\n\nA pre-generics `.class` file and a generics-aware one produce **compatible**\nbytecode, and a `List` from old code can flow into new generic code.\n**Rule of thumb:** erasure was the price of adding generics without forking\nthe platform — runtime reification (like C#) would have broken the existing\necosystem.\n",{"id":2442,"difficulty":126,"q":2443,"a":2444},"how-compiler-erases","How exactly does the compiler erase generic types?","The compiler applies three transformations: it **replaces type parameters**\nwith their leftmost bound (or `Object` if unbounded), **inserts casts** at\nevery site where erased values are read out, and **generates bridge methods**\nto preserve polymorphism. The runtime never sees `T`.\n\n```java\n\u002F\u002F You write:\nclass Box\u003CT> { T value; T get() { return value; } }\nString s = new Box\u003CString>().get();\n\n\u002F\u002F After erasure (conceptually):\nclass Box { Object value; Object get() { return value; } }\nString s = (String) new Box().get();   \u002F\u002F compiler inserts the cast\n```\n\nA bounded `\u003CT extends Number>` erases to `Number`, not `Object`.\n**Rule of thumb:** type parameter -> bound, plus compiler-inserted casts — the\ncasts are guaranteed safe because the compiler already type-checked the code.\n",{"id":2446,"difficulty":105,"q":2447,"a":2448},"erasure-to-bound","What does a bounded type parameter erase to?","A type parameter erases to its **leftmost (first) bound**, not always `Object`.\nAn unbounded `\u003CT>` erases to `Object`, but `\u003CT extends Number>` erases to\n`Number`, which lets the compiler call `Number` methods directly on `T`.\n\n```java\n\u003CT extends Number> double sum(T a, T b) {\n  return a.doubleValue() + b.doubleValue(); \u002F\u002F legal — T erases to Number\n}\n\u002F\u002F erased signature: double sum(Number a, Number b)\n\n\u003CT extends Comparable\u003CT> & Serializable> T pick(T x) { return x; }\n\u002F\u002F erases to Comparable (the FIRST bound)\n```\n\nWith multiple bounds (`A & B`), only the **first** drives erasure; that's why\nyou put the class or most-used interface first. **Rule of thumb:** the erased\ntype is the first bound — choose bound order so the useful methods survive.\n",{"id":2450,"difficulty":126,"q":2451,"a":2452},"reifiable-vs-non-reifiable","What is the difference between reifiable and non-reifiable types?","A **reifiable** type is one whose type information is **fully available at\nruntime** — its representation is complete after erasure. A **non-reifiable**\ntype loses information to erasure, so the JVM can't fully reconstruct it.\n\n| Reifiable (survives) | Non-reifiable (erased) |\n| -------------------- | ---------------------- |\n| `String`, `Integer` | `List\u003CString>` |\n| `List`, `Map` (raw) | `List\u003C? extends Number>` |\n| `List\u003C?>` (unbounded wildcard) | `T` (type parameter) |\n| `int[]`, `String[]` | `List\u003CString>[]` |\n\n```java\no instanceof List\u003C?>      \u002F\u002F legal — unbounded wildcard is reifiable\no instanceof List\u003CString> \u002F\u002F ERROR — non-reifiable, info was erased\n```\n\n**Rule of thumb:** if a type still carries a generic argument other than `?`,\nit's non-reifiable and you can't use it with `instanceof`, array creation, or\n`.class`.\n",{"id":2454,"difficulty":105,"q":2455,"a":2456},"no-class-literal","Why is List\u003CString>.class not allowed?","Because there is only **one `Class` object** for `List`, shared by every\nparameterization. After erasure `List\u003CString>`, `List\u003CInteger>`, and raw\n`List` are the same class, so a `List\u003CString>.class` literal would be\nmeaningless — there's nothing distinct to point to.\n\n```java\nClass\u003C?> c = List.class;          \u002F\u002F legal — the one List class\nClass\u003C?> d = List\u003CString>.class;  \u002F\u002F compile error\nList\u003CString> a = new ArrayList\u003C>();\nList\u003CInteger> b = new ArrayList\u003C>();\nSystem.out.println(a.getClass() == b.getClass()); \u002F\u002F true\n```\n\n`getClass()` on any generic instance returns the **raw** class object for the\nsame reason. **Rule of thumb:** there's one `Class` per erased type, so a\nparameterized class literal can't exist.\n",{"id":2458,"difficulty":126,"q":763,"a":2459},"cannot-instantiate-t","Because at runtime `T` has been erased — the JVM has **no idea which class** to\ninstantiate, and it can't guarantee `T` even has a no-arg constructor. The\n`new` bytecode needs a concrete class, which erasure has removed.\n\n```java\nclass Factory\u003CT> {\n  T make() { return new T(); }   \u002F\u002F compile error — cannot instantiate T\n}\n\n\u002F\u002F Workaround: pass a Class token or a supplier\nclass Factory\u003CT> {\n  T make(Class\u003CT> type) throws Exception {\n    return type.getDeclaredConstructor().newInstance(); \u002F\u002F reflection\n  }\n  T make(Supplier\u003CT> s) { return s.get(); }             \u002F\u002F cleaner\n}\n```\n\n**Rule of thumb:** to create instances of a type parameter, pass in a\n`Class\u003CT>` token or a `Supplier\u003CT>` — the type must come from somewhere\nreifiable.\n",{"id":766,"difficulty":126,"q":2461,"a":2462},"Why can't you create a generic array like new T[] or new List\u003CString>[]?","Arrays are **reified** — they remember and **enforce their element type at\nruntime** (storing a wrong type throws `ArrayStoreException`). Generics are\n**erased**. The two models are incompatible: a generic array couldn't perform\nits runtime store-check because the element type was erased.\n\n```java\nT[] a = new T[10];               \u002F\u002F compile error — generic array creation\nList\u003CString>[] b = new List\u003CString>[10]; \u002F\u002F compile error\n\n\u002F\u002F Workarounds:\nList\u003CString>[] c = (List\u003CString>[]) new List[10]; \u002F\u002F unchecked cast\nT[] d = (T[]) Array.newInstance(componentType, 10); \u002F\u002F reflection + Class token\n```\n\n**Rule of thumb:** you can't directly create arrays of a non-reifiable type;\nuse a `List\u003CList\u003CString>>` or an unchecked cast from a raw array.\n",{"id":2464,"difficulty":126,"q":2465,"a":2466},"heap-pollution","What is heap pollution and how do generic arrays cause it?","**Heap pollution** occurs when a variable of a parameterized type points to an\nobject that is **not** of that type — usually because erasure let an\nincompatible value slip in. Generic arrays are banned precisely because they'd\nmake this trivially easy and undetectable.\n\n```java\nList\u003CString>[] arr = (List\u003CString>[]) new List[1]; \u002F\u002F unchecked\nObject[] objs = arr;                  \u002F\u002F arrays are covariant\nobjs[0] = List.of(42);                \u002F\u002F stores List\u003CInteger> — no error!\nString s = arr[0].get(0);             \u002F\u002F ClassCastException at READ time\n```\n\nThe corruption is silent until a later read fails far from the cause.\n**Rule of thumb:** heap pollution = a generic variable holding the wrong\nelement type; it surfaces as a surprise `ClassCastException` from\ncompiler-inserted casts.\n",{"id":2468,"difficulty":105,"q":2469,"a":2470},"instanceof-generics","Why can't you use instanceof with a parameterized type?","`instanceof` is a **runtime** check, but the generic type argument was\n**erased**, so there's nothing to test against. The JVM could only tell you\nit's a `List`, never a `List\u003CString>`. Only **reifiable** types (raw types or\nthe unbounded wildcard) are allowed.\n\n```java\nif (obj instanceof List\u003CString>) { } \u002F\u002F compile error\nif (obj instanceof List\u003C?>) { }       \u002F\u002F OK — unbounded wildcard is reifiable\nif (obj instanceof List) { }          \u002F\u002F OK — raw type\n\n@SuppressWarnings(\"unchecked\")\nList\u003CString> l = (List\u003CString>) obj;  \u002F\u002F cast compiles but is unchecked\n```\n\n**Rule of thumb:** check against `List\u003C?>` or the raw `List`; you can never\n`instanceof` a specific type argument because it doesn't exist at runtime.\n",{"id":2472,"difficulty":126,"q":2473,"a":2474},"bridge-methods","What are bridge methods and why does the compiler generate them?","A **bridge method** is a synthetic method the compiler generates to **preserve\npolymorphism** after erasure. When a generic supertype's method erases to a\ndifferent signature than the subtype's override, the compiler adds a bridge so\ndynamic dispatch still finds the real method.\n\n```java\nclass Node\u003CT> { void set(T t) { } }            \u002F\u002F erases to set(Object)\nclass StringNode extends Node\u003CString> {\n  @Override void set(String s) { }             \u002F\u002F set(String)\n}\n\u002F\u002F Compiler adds a synthetic bridge in StringNode:\n\u002F\u002F void set(Object o) { set((String) o); }      \u002F\u002F forwards to the real method\n```\n\nWithout the bridge, `Node\u003CString> n = new StringNode(); n.set(\"x\")` would call\nthe inherited `set(Object)` and skip the override. **Rule of thumb:** bridge\nmethods are invisible glue that keep overriding working across erased generic\nsignatures.\n",{"id":2476,"difficulty":105,"q":2477,"a":2478},"bridge-method-visibility","How can you tell a bridge method apart from a real one?","Bridge methods are marked **synthetic** and carry the **`ACC_BRIDGE`** flag in\nthe bytecode. You can detect them at runtime via reflection with\n`Method.isBridge()` and `Method.isSynthetic()`. They never appear in your\nsource and you shouldn't call them directly.\n\n```java\nfor (Method m : StringNode.class.getDeclaredMethods()) {\n  System.out.println(m + \" bridge=\" + m.isBridge());\n}\n\u002F\u002F set(String) bridge=false\n\u002F\u002F set(Object) bridge=true   \u003C- the synthetic bridge\n```\n\nThey're why reflective scans sometimes find \"duplicate\" methods that differ\nonly by parameter type. **Rule of thumb:** filter out `isBridge()`\u002F\n`isSynthetic()` methods when introspecting generic classes.\n",{"id":2480,"difficulty":126,"q":2481,"a":2482},"overload-clash","Why won't two methods that differ only by generic type parameter compile?","Because after erasure they have the **same signature**, and a class can't have\ntwo methods with identical signatures. The compiler reports a **\"name clash\"**\neven though the source-level parameter types look different.\n\n```java\nclass Printer {\n  void print(List\u003CString> s) { }   \u002F\u002F erases to print(List)\n  void print(List\u003CInteger> i) { }  \u002F\u002F also erases to print(List) — CLASH!\n}\n\u002F\u002F error: name clash: both methods have the same erasure\n```\n\nThe fix is to give them genuinely different erased signatures (different raw\ntypes or arity) or rename one. **Rule of thumb:** overloads must differ after\nerasure — distinct type arguments alone are not enough.\n",{"id":2484,"difficulty":126,"q":2485,"a":2486},"class-token-pattern","What is the Class\u003CT> type token pattern and why is it useful?","A **type token** is a `Class\u003CT>` object passed in to **recover the type\ninformation** that erasure removed. Since the type argument is gone at runtime,\nhanding the method a `Class\u003CT>` lets it instantiate, cast, or check types\nsafely.\n\n```java\n\u003CT> T fromJson(String json, Class\u003CT> type) {\n  Object parsed = parse(json);\n  return type.cast(parsed);          \u002F\u002F typed cast via the token\n}\nUser u = fromJson(s, User.class);     \u002F\u002F T inferred from the token\n\n\u003CT> T create(Class\u003CT> type) throws Exception {\n  return type.getDeclaredConstructor().newInstance();\n}\n```\n\nFrameworks like Jackson and Spring rely on this everywhere.\n**Rule of thumb:** when you need the runtime type of `T`, pass a `Class\u003CT>`\ntoken — it's the standard escape hatch from erasure.\n",{"id":2488,"difficulty":126,"q":2489,"a":2490},"super-type-token","How do super type tokens (TypeReference) capture generic types at runtime?","A plain `Class\u003CT>` token can't represent a **parameterized** type like\n`List\u003CString>` (no such class literal). The **super type token** trick (used by\nJackson's `TypeReference`, Guava's `TypeToken`) captures it by subclassing an\nabstract generic class and reading the type argument via reflection from the\n**generic superclass**, which the compiler *does* record.\n\n```java\n\u002F\u002F The anonymous subclass embeds List\u003CString> in its signature:\nTypeReference\u003CList\u003CString>> ref = new TypeReference\u003CList\u003CString>>() {};\n\u002F\u002F Internally:\nType t = getClass().getGenericSuperclass();           \u002F\u002F TypeReference\u003CList\u003CString>>\nType arg = ((ParameterizedType) t).getActualTypeArguments()[0]; \u002F\u002F List\u003CString>\n```\n\nGeneric type info on **class\u002Fmethod signatures** survives erasure (in metadata),\neven though instance-level arguments don't. **Rule of thumb:** subclassing a\ngeneric type pins its arguments in the class signature, which reflection can\nread back.\n",{"id":2492,"difficulty":105,"q":2493,"a":2494},"static-field-no-type-param","Why can't a static field or static context use the class type parameter?","A type parameter belongs to a **specific instance's** parameterization, but a\n**static** member is shared across **all** parameterizations — and after\nerasure there's only one class anyway. There's no single `T` for the static\ncontext to refer to, so it's forbidden.\n\n```java\nclass Box\u003CT> {\n  static T shared;              \u002F\u002F compile error — T in static context\n  static void set(T t) { }      \u002F\u002F compile error\n  static \u003CU> U pick(U u) { return u; } \u002F\u002F OK — its OWN type parameter\n}\n```\n\nA static **method** may declare its **own** type parameter, which is fine.\n**Rule of thumb:** the class's `T` is per-instance; statics are class-wide, so\nthey can't use it — give a static method its own type parameter instead.\n",{"id":2496,"difficulty":126,"q":2497,"a":2498},"generic-exceptions","What are the restrictions on generics with exceptions?","A generic class **cannot extend `Throwable`**, and you **cannot catch a type\nparameter**, because `catch` is a runtime dispatch on the exception's actual\nclass — which erasure has removed. You *can* declare a method that **throws**\na type parameter bounded by `Throwable`.\n\n```java\nclass MyException\u003CT> extends Exception { }  \u002F\u002F compile error — generic Throwable\n\n\u003CT extends Throwable> void run() {\n  try { \u002F* ... *\u002F }\n  catch (T e) { }              \u002F\u002F compile error — cannot catch type parameter\n}\n\n\u003CT extends Throwable> void rethrow(T t) throws T { throw t; } \u002F\u002F OK\n```\n\nIf catch were allowed, two `catch (T)` clauses could erase to the same\n`catch (Exception)`. **Rule of thumb:** you can throw but never catch a type\nparameter, and exception classes can't be generic.\n",{"id":2500,"difficulty":105,"q":2501,"a":2502},"runtime-type-info-survives","What generic type information actually survives erasure?","Instance type arguments vanish, but generic info embedded in **declarations** is\nkept in the class file's signature metadata and is readable via reflection\n(`java.lang.reflect.Type`). This includes field types, method\nparameter\u002Freturn types, type variable bounds, and the **generic superclass \u002F\ninterfaces**.\n\n```java\nclass Repo { List\u003CString> names; }\nField f = Repo.class.getDeclaredField(\"names\");\nType t = f.getGenericType();                 \u002F\u002F List\u003CString> — preserved!\nParameterizedType pt = (ParameterizedType) t;\nSystem.out.println(pt.getActualTypeArguments()[0]); \u002F\u002F class java.lang.String\n```\n\nWhat's lost is the argument of a **runtime object** (`new ArrayList\u003CString>()`\nknows nothing about `String`). **Rule of thumb:** declaration-site generics\nlive in metadata; use-site instance generics do not.\n",{"id":2504,"difficulty":105,"q":2505,"a":2506},"safevarargs","What does @SafeVarargs do and how does it relate to erasure?","A **varargs parameter of a generic type** creates a generic array under the\nhood (`T...` becomes `T[]`), which triggers an unavoidable **unchecked \u002F\n\"possible heap pollution\"** warning. `@SafeVarargs` is your assertion that the\nmethod **only reads** from the varargs and never pollutes the array, which\nsuppresses the warning at the declaration and all call sites.\n\n```java\n@SafeVarargs\nstatic \u003CT> List\u003CT> listOf(T... items) {   \u002F\u002F T[] is a non-reifiable array\n  return new ArrayList\u003C>(Arrays.asList(items)); \u002F\u002F safe — read only\n}\n```\n\nIt's applicable only to methods that **can't be overridden** (`static`,\n`final`, or `private`). **Rule of thumb:** use `@SafeVarargs` when your\ngeneric varargs method is read-only and provably safe from heap pollution.\n",{"id":2508,"difficulty":105,"q":2509,"a":2510},"unchecked-warnings","What is an unchecked warning and why does erasure cause it?","An **unchecked warning** means the compiler **can't verify the type safety** of\nan operation because the needed type information was erased — typically a cast\nto a parameterized type or use of a raw type. The code compiles, but the\ncompiler is telling you it can't guarantee the runtime cast won't fail.\n\n```java\nObject o = new ArrayList\u003CString>();\nList\u003CString> list = (List\u003CString>) o; \u002F\u002F unchecked — only List is verifiable\n\nList raw = new ArrayList();\nraw.add(\"x\");                          \u002F\u002F unchecked call to add(E)\n```\n\nSuppress only when you've manually proven safety, with the **narrowest scope**\nand a comment, via `@SuppressWarnings(\"unchecked\")`. **Rule of thumb:** an\nunchecked warning is erasure admitting it can't check you — treat each one as a\npotential `ClassCastException` to justify.\n",{"id":2512,"difficulty":126,"q":2513,"a":2514},"erasure-vs-reification","How does Java's erasure differ from reified generics in languages like C#?","With **reified generics** (C#\u002F.NET), the type argument is **preserved at\nruntime**: `List\u003Cint>` and `List\u003Cstring>` are distinct types, you can call\n`typeof(T)`, do `new T()`, and use `is List\u003Cstring>`. Java's **erased**\ngenerics throw all of that away after compilation.\n\n```java\n\u002F\u002F Java — none of these work:\nT.class;  new T();  new T[10];  obj instanceof List\u003CString>;\n\n\u002F\u002F C# equivalents all work because T is reified at runtime.\n```\n\nReification costs a specialized type per parameterization and breaks legacy\ninterop; erasure is cheaper and compatible but loses runtime type identity.\n**Rule of thumb:** Java traded runtime type knowledge for backward\ncompatibility — every generics restriction you hit traces back to that choice.\n",{"description":103},"Java type erasure interview questions — how the compiler erases generics, bridge methods, reifiable vs non-reifiable types, generics and arrays, restrictions on generics, and runtime type information.","java\u002Fgenerics\u002Ftype-erasure","Rh7iwMUxEBeSRusc_Z0L9khTTqt-GzkevYFbBvte82E",{"id":2520,"title":2521,"body":2522,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":2526,"navigation":108,"order":38,"path":2527,"questions":2528,"questionsCount":980,"related":250,"seo":2589,"seoDescription":2590,"stem":2591,"subtopic":2592,"topic":81,"topicSlug":83,"updated":809,"__hash__":2593},"qa\u002Fjava\u002Fjvm-internals\u002Fclassloading.md","Classloading",{"type":100,"value":2523,"toc":2524},[],{"title":103,"searchDepth":29,"depth":29,"links":2525},[],{},"\u002Fjava\u002Fjvm-internals\u002Fclassloading",[2529,2533,2537,2541,2545,2549,2553,2557,2561,2565,2569,2573,2577,2581,2585],{"id":2530,"difficulty":113,"q":2531,"a":2532},"what-is-classloading","What is class loading in the JVM?","**Class loading** is the process by which the JVM reads a `.class` file\n(bytecode), parses it, and creates the corresponding `java.lang.Class`\nobject in memory. A class is loaded **on demand** the first time it is\nreferenced by running code — not upfront at JVM startup.\n\n```java\n\u002F\u002F When this line executes for the first time:\nMyService svc = new MyService();\n\u002F\u002F The JVM loads MyService.class if it hasn't been loaded yet,\n\u002F\u002F resolves its dependencies, initialises static fields, then calls new.\n```\n\n**Rule of thumb:** classes are loaded lazily; the JVM only reads a\n`.class` file the first time that class is actually needed.\n",{"id":2534,"difficulty":105,"q":2535,"a":2536},"classloader-types","What are the built-in ClassLoaders in the JVM and what does each load?","The JVM ships with a **hierarchy of ClassLoaders**:\n\n| ClassLoader | Java 8 name | Java 9+ name | Loads |\n|---|---|---|---|\n| Bootstrap | Bootstrap CL | Bootstrap CL | Core JDK classes (`java.lang.*`, `java.util.*`) from `rt.jar` \u002F `java.base` module |\n| Extension \u002F Platform | Extension CL | Platform CL | `javax.*`, security providers; in Java 9+ it loads named JDK modules not in `java.base` |\n| Application | App \u002F System CL | App CL | Classes from the user **classpath** (`-cp`) or module path |\n\n```java\nSystem.out.println(String.class.getClassLoader());        \u002F\u002F null (Bootstrap)\nSystem.out.println(ClassLoader.getSystemClassLoader());   \u002F\u002F AppClassLoader\nSystem.out.println(MyApp.class.getClassLoader());         \u002F\u002F AppClassLoader\n```\n\n**Rule of thumb:** `null` for a class's ClassLoader means it was loaded by\nthe Bootstrap ClassLoader — the JVM doesn't expose a Java object for it.\n",{"id":2538,"difficulty":105,"q":2539,"a":2540},"delegation-model","What is the parent-delegation model for class loading?","Before loading a class, a ClassLoader **delegates to its parent** first.\nIf the parent (or its parent) can load the class, that result is used.\nOnly if the parent chain cannot find the class does the current loader\nattempt to load it itself. This ensures that core JDK classes loaded by\nBootstrap always take precedence.\n\n```\nAppClassLoader.loadClass(\"com.example.MyClass\")\n    → delegates to PlatformClassLoader\n        → delegates to BootstrapClassLoader\n            → not found in rt.jar \u002F java.base\n        ← BootstrapClassLoader returns null\n    ← PlatformClassLoader returns null\n→ AppClassLoader loads from classpath ✓\n```\n\n**Rule of thumb:** parent-delegation prevents a rogue `java\u002Flang\u002FString.class`\non the classpath from shadowing the real `String` — the Bootstrap loader\nalways wins for JDK classes.\n",{"id":2542,"difficulty":105,"q":2543,"a":2544},"loading-linking-initialisation","What are the three phases of class loading — loading, linking, and initialisation?","**Loading** — reads the binary class data (from a file, JAR, network, etc.)\nand creates the `Class\u003C?>` object. The bytecode is not yet verified.\n\n**Linking** — three sub-steps:\n1. **Verification** — checks that the bytecode is structurally correct and\n   won't violate JVM safety guarantees.\n2. **Preparation** — allocates memory for static fields and sets them to\n   their **default values** (`0`, `null`, `false`) — *not* the values in\n   initialiser code yet.\n3. **Resolution** — resolves symbolic references (class names, method\n   descriptors) in the constant pool to actual memory addresses (optional\n   at link time; may be deferred).\n\n**Initialisation** — runs the class's `\u003Cclinit>` method (static initialisers\nand static field assignments) **exactly once**, the first time the class\nis actively used.\n\n```java\nclass Config {\n    static int LIMIT = Integer.parseInt(System.getenv(\"LIMIT\")); \u002F\u002F runs in \u003Cclinit>\n}\n```\n\n**Rule of thumb:** static fields are zeroed during *preparation*, then set\nto their real values during *initialisation* — never assume a static field\nholds its declared value before the class is initialised.\n",{"id":2546,"difficulty":105,"q":2547,"a":2548},"class-identity","What is class identity in the JVM and why can two classes with the same name be different?","A class in the JVM is identified by **both its fully qualified name and its\nClassLoader**. Two `Class\u003C?>` objects are the **same class** only if both\nthe name and the ClassLoader instance match.\n\nThis is why frameworks like Java EE application servers, OSGi, and hot-deploy\nsystems use **separate ClassLoaders per deployment** — each application gets\nits own `com.example.Service`, isolated from others.\n\n```java\nClassLoader cl1 = new URLClassLoader(urls);\nClassLoader cl2 = new URLClassLoader(urls);\nClass\u003C?> a = cl1.loadClass(\"com.example.Foo\");\nClass\u003C?> b = cl2.loadClass(\"com.example.Foo\");\nSystem.out.println(a == b);              \u002F\u002F false — different loaders\nSystem.out.println(a.equals(b));         \u002F\u002F false\n\u002F\u002F Casting between them would throw ClassCastException\n```\n\n**Rule of thumb:** class identity = (fully-qualified name, ClassLoader);\nthe same `.class` file loaded by two different ClassLoaders produces two\nincompatible types.\n",{"id":2550,"difficulty":105,"q":2551,"a":2552},"classnotfoundexception-vs-noclassdeffounderror","What is the difference between ClassNotFoundException and NoClassDefFoundError?","| | `ClassNotFoundException` | `NoClassDefFoundError` |\n|---|---|---|\n| Type | Checked exception | Error (unchecked) |\n| When | `Class.forName()`, `ClassLoader.loadClass()` called explicitly and the class is not on the classpath | Class was available at **compile time** but missing at **runtime** (e.g., JAR not deployed) |\n| Cause | Developer error: typo in class name, missing dependency at runtime | Deployment error: class was compiled against a JAR that is absent at runtime |\n\n```java\n\u002F\u002F ClassNotFoundException — explicit dynamic load\nClass.forName(\"com.mysql.jdbc.Driver\"); \u002F\u002F throws if MySQL JAR is missing\n\n\u002F\u002F NoClassDefFoundError — implicit reference to a class present at compile time\n\u002F\u002F but missing at runtime — JVM throws this from its own resolution code\n```\n\n**Rule of thumb:** `ClassNotFoundException` = you asked for a class by name\nand it wasn't there; `NoClassDefFoundError` = the JVM needed a class while\nloading another and couldn't find it.\n",{"id":2554,"difficulty":126,"q":2555,"a":2556},"custom-classloader","Why would you write a custom ClassLoader and how do you do it?","Custom ClassLoaders let you load classes from non-standard sources:\nencrypted JARs, databases, over a network, generated bytecode at runtime,\nor isolated namespaces (plugins, hot-reload, OSGi bundles).\n\n```java\npublic class EncryptedClassLoader extends ClassLoader {\n    private final Path jarPath;\n\n    EncryptedClassLoader(Path p, ClassLoader parent) {\n        super(parent);           \u002F\u002F always wire up the parent for delegation\n        this.jarPath = p;\n    }\n\n    @Override\n    protected Class\u003C?> findClass(String name) throws ClassNotFoundException {\n        byte[] decrypted = decrypt(readBytesFromJar(jarPath, name));\n        return defineClass(name, decrypted, 0, decrypted.length);\n    }\n}\n```\n\nOverride `findClass()`, not `loadClass()`, to preserve the parent-delegation\nmodel. Call `defineClass()` with the raw bytecode to register the class with\nthe JVM.\n\n**Rule of thumb:** override `findClass()`, not `loadClass()` — breaking\ndelegation opens the door to shadowing core JDK classes.\n",{"id":2558,"difficulty":126,"q":2559,"a":2560},"class-unloading","When does the JVM unload a class and why is this important for dynamic systems?","A class can be **unloaded** (and its `Class\u003C?>` object GC'd) only when\nits **ClassLoader** instance becomes unreachable. The Bootstrap ClassLoader\nnever becomes unreachable, so core JDK classes are never unloaded. Classes\nloaded by the Application ClassLoader are effectively permanent too (the\nloader lives as long as the JVM).\n\nClasses *can* be unloaded when:\n- They were loaded by a **custom ClassLoader** (e.g., a plugin loader).\n- All Class objects, all instances, and the ClassLoader itself have no\n  strong references.\n\n```java\nURLClassLoader pluginLoader = new URLClassLoader(urls, parent);\nClass\u003C?> pluginClass = pluginLoader.loadClass(\"com.plugin.Plugin\");\n\u002F\u002F ... use the plugin ...\npluginLoader.close();    \u002F\u002F no more strong ref to loader or class\npluginLoader = null;\n\u002F\u002F Now the GC can unload the plugin class and reclaim Metaspace\n```\n\nMetaspace leaks in hot-deploy scenarios (e.g., Tomcat web app reload) are\nalmost always caused by something outside the webapp's ClassLoader still\nholding a reference to the loader or one of its classes.\n\n**Rule of thumb:** if Metaspace grows after each hot-deploy, hunt for\nreferences to the old ClassLoader held in static fields or thread locals.\n",{"id":2562,"difficulty":105,"q":2563,"a":2564},"static-initialiser","What guarantees does the JVM provide about class initialisation and static initialisers?","The JVM guarantees that a class's `\u003Cclinit>` (static initialiser block and\nstatic field assignments) runs **exactly once**, **before** any instance of\nthe class is created or any static member is accessed, and is\n**thread-safe** — the JVM uses an internal lock so that even if two threads\nrace to initialise the same class, only one runs `\u003Cclinit>` and the other\nwaits.\n\n```java\nclass Singleton {\n    private static final Singleton INSTANCE = new Singleton(); \u002F\u002F safe, runs once\n\n    static {\n        System.out.println(\"Initialising Singleton\");\n    }\n}\n```\n\nThis guarantee is what makes the **Initialization-on-demand Holder** idiom\nthread-safe without explicit synchronisation:\n\n```java\nclass Holder {\n    private Holder() {}\n    private static class Inner { static final Holder INSTANCE = new Holder(); }\n    static Holder getInstance() { return Inner.INSTANCE; }\n}\n\u002F\u002F Inner is not loaded until getInstance() is first called;\n\u002F\u002F JVM ensures thread-safe single initialisation\n```\n\n**Rule of thumb:** static initialisers are guaranteed to run once and\nsafely — this is the foundation of the holder singleton pattern.\n",{"id":2566,"difficulty":113,"q":2567,"a":2568},"class-forname","What does Class.forName() do and what are its overloads?","`Class.forName(String name)` loads and **initialises** the named class\nusing the calling class's ClassLoader. The two-argument overload gives you\ncontrol over both:\n\n```java\n\u002F\u002F Simple form: loads + initialises using caller's ClassLoader\nClass\u003C?> clazz = Class.forName(\"com.example.MyPlugin\");\n\n\u002F\u002F Full control: Class.forName(name, initialize, loader)\nClass\u003C?> lazy = Class.forName(\"com.example.MyPlugin\",\n                              false,              \u002F\u002F don't initialise yet\n                              customLoader);      \u002F\u002F use this ClassLoader\n```\n\nThe classic use case is **JDBC driver registration** (pre-JDBC 4):\n`Class.forName(\"com.mysql.jdbc.Driver\")` loaded and initialised the driver\nclass, whose static block registered it with `DriverManager`. JDBC 4+\nuses `ServiceLoader` to do this automatically.\n\n**Rule of thumb:** `Class.forName(name)` = load + initialise;\n`Class.forName(name, false, loader)` = load only, defer initialisation.\n",{"id":2570,"difficulty":126,"q":2571,"a":2572},"module-system-classloading","How did the Java 9 module system change class loading?","Before Java 9, the JDK was a monolithic `rt.jar` loaded by Bootstrap.\nJava 9 introduced the **module system (JPMS)**, splitting the JDK into\nnamed modules (`java.base`, `java.sql`, `java.logging`, etc.).\n\nKey changes:\n- **Bootstrap ClassLoader** now loads only `java.base` and a few core\n  modules; no more `rt.jar`.\n- **Platform ClassLoader** (renamed from Extension CL) loads the remaining\n  JDK modules.\n- Module boundaries enforce **strong encapsulation** — a module must\n  explicitly `exports` a package for code in other modules to access it;\n  deep reflection into non-exported packages requires `--add-opens`.\n\n```bash\n# Allow reflection into java.base internals (needed by some frameworks):\njava --add-opens java.base\u002Fjava.lang=ALL-UNNAMED -jar myapp.jar\n```\n\nClass loading *mechanics* (parent delegation, `defineClass`) are unchanged;\nwhat changed is the *source* of classes and what is accessible.\n\n**Rule of thumb:** JPMS changes *where* classes come from and *what* is\naccessible; the fundamental ClassLoader delegation chain still applies.\n",{"id":2574,"difficulty":105,"q":2575,"a":2576},"serviceloader","What is ServiceLoader and how does it relate to class loading?","`java.util.ServiceLoader` is a lightweight **plugin \u002F SPI mechanism** that\ndynamically discovers and loads implementations of an interface registered\nin `META-INF\u002Fservices\u002F\u003Cinterface-name>` (or via `module-info.java`\n`provides` in modules).\n\n```java\n\u002F\u002F In META-INF\u002Fservices\u002Fcom.example.Plugin:\n\u002F\u002F com.example.impl.FooPlugin\n\nServiceLoader\u003CPlugin> loader = ServiceLoader.load(Plugin.class);\nfor (Plugin p : loader) {\n    p.execute(); \u002F\u002F each registered implementation is loaded and instantiated\n}\n```\n\nJDBC 4.0 drivers use `ServiceLoader` to auto-register without\n`Class.forName()`. Frameworks like SLF4J, Jackson, and JCA rely on it\nfor extensibility.\n\n**Rule of thumb:** `ServiceLoader` is the standard way to decouple an API\nfrom its implementation — prefer it over `Class.forName()` for plugin\narchitectures.\n",{"id":2578,"difficulty":126,"q":2579,"a":2580},"classloader-leak","What is a ClassLoader leak and how do you detect and fix it?","A **ClassLoader leak** occurs when a custom ClassLoader (e.g., a web app\nloader in Tomcat) cannot be garbage collected after the app is undeployed\nbecause something outside the loader still holds a reference to it or to\na class\u002Fobject loaded by it. Because the loader can't be GC'd, neither can\nany of its classes — Metaspace grows with each redeploy.\n\nCommon causes:\n- **ThreadLocal values** whose type was loaded by the webapp loader, not\n  cleared before undeployment.\n- **Static fields in a shared library** (loaded by the parent ClassLoader)\n  holding a reference to an object of a webapp class.\n- **JDBC drivers** registered with `DriverManager` and never deregistered.\n- **Logging frameworks** holding class references in static config.\n\n```java\n\u002F\u002F Fix: deregister on shutdown\n@Override\npublic void contextDestroyed(ServletContextEvent sce) {\n    Enumeration\u003CDriver> drivers = DriverManager.getDrivers();\n    while (drivers.hasMoreElements()) DriverManager.deregisterDriver(drivers.nextElement());\n    \u002F\u002F Also clear any ThreadLocals your code set\n}\n```\n\nDetect with a heap dump: look for `ClassLoader` instances that should have\nbeen unloaded; trace their retaining references with Eclipse MAT.\n\n**Rule of thumb:** every object allocated in a web app that lives beyond\nthe request must be cleaned up in a `ServletContextListener.contextDestroyed`\n— otherwise it anchors the ClassLoader forever.\n",{"id":2582,"difficulty":105,"q":2583,"a":2584},"bootstrap-classloader","Why does String.class.getClassLoader() return null?","The **Bootstrap ClassLoader** is implemented in native code (C\u002FC++) inside\nthe JVM itself, not as a Java class. It has no Java object representation,\nso the JVM signals \"loaded by Bootstrap\" by returning **`null`** from\n`getClassLoader()`.\n\n```java\nSystem.out.println(String.class.getClassLoader());         \u002F\u002F null\nSystem.out.println(int.class.getClassLoader());            \u002F\u002F null (primitive)\nSystem.out.println(MyApp.class.getClassLoader());          \u002F\u002F sun.misc.Launcher$AppClassLoader\n```\n\nThis is a conventional signal, not an error. Code that uses ClassLoaders\nmust handle `null` and interpret it as Bootstrap:\n\n```java\nClassLoader cl = SomeClass.class.getClassLoader();\nClassLoader toUse = (cl != null) ? cl : ClassLoader.getSystemClassLoader();\n```\n\n**Rule of thumb:** `null` ClassLoader = Bootstrap = JDK core class; always\nnull-check before using a class's ClassLoader as an argument.\n",{"id":2586,"difficulty":126,"q":2587,"a":2588},"hotswap-and-dynamic-reloading","How does Java support hot-swapping or dynamic class reloading?","The standard JVM supports limited **HotSwap** via JPDA (Java Platform\nDebugger Architecture) — you can redefine a class's method bodies at\nruntime in a debug session without restarting. It cannot change class\nstructure (fields, superclasses, interfaces).\n\nFor full hot-reload (new fields, new classes, new hierarchies), the two\napproaches are:\n\n1. **Reload via a new ClassLoader** — create a fresh `URLClassLoader`,\n   discard the old loader and all its instances, let GC clean up.\n   Used by Tomcat, OSGi, and Java EE containers.\n2. **Bytecode manipulation agents** — tools like **JRebel** or\n   **HotswapAgent** use the `java.lang.instrument` API to redefine class\n   bytecode at runtime, including structural changes. Requires a `-javaagent`\n   flag at startup.\n\n```bash\njava -javaagent:hotswap-agent.jar MyApp\n```\n\n**Rule of thumb:** for dev-time hot reload of full structural changes use\na ClassLoader-per-deployment strategy or an instrumentation agent; for\nminor method-body fixes in a running debugger, JPDA HotSwap is sufficient.\n",{"description":103},"Java class loading interview questions — ClassLoader hierarchy, delegation model, loading\u002Flinking\u002Finitialisation phases, custom ClassLoaders, class unloading, ClassNotFoundException vs NoClassDefFoundError, and module system changes.","java\u002Fjvm-internals\u002Fclassloading","Class Loading","K2ocnQi7twugrD-1hx8TJCVNGyuBOlFfy2lyxSPDQ14",{"id":2595,"title":2596,"body":2597,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":2601,"navigation":108,"order":38,"path":2602,"questions":2603,"questionsCount":1835,"related":250,"seo":2660,"seoDescription":2661,"stem":2662,"subtopic":2596,"topic":90,"topicSlug":92,"updated":809,"__hash__":2663},"qa\u002Fjava\u002Fmodern-java\u002Fswitch-pattern-matching.md","Switch Pattern Matching",{"type":100,"value":2598,"toc":2599},[],{"title":103,"searchDepth":29,"depth":29,"links":2600},[],{},"\u002Fjava\u002Fmodern-java\u002Fswitch-pattern-matching",[2604,2608,2612,2616,2620,2624,2628,2632,2636,2640,2644,2648,2652,2656],{"id":2605,"difficulty":113,"q":2606,"a":2607},"switch-expression-vs-statement","What is the difference between a switch statement and a switch expression?","A **switch statement** is an imperative control-flow construct that\nexecutes code for a matching case. A **switch expression** (Java 14,\nJEP 361) is an expression that **produces a value** and can be used\nanywhere an expression is expected.\n\n```java\n\u002F\u002F Switch statement — imperative, returns nothing\nString msg;\nswitch (day) {\n    case MONDAY: msg = \"start\"; break;\n    default:     msg = \"other\";\n}\n\n\u002F\u002F Switch expression — yields a value\nString msg = switch (day) {\n    case MONDAY -> \"start\";\n    default     -> \"other\";\n};\n```\n\nSwitch expressions use **arrow labels** (`->`) which don't fall through\nand don't need `break`. They must be **exhaustive** — every possible value\nmust be handled.\n\n**Rule of thumb:** prefer switch expressions over switch statements;\nthey're concise, don't fall through, and the compiler enforces exhaustiveness.\n",{"id":2609,"difficulty":113,"q":2610,"a":2611},"arrow-vs-colon-syntax","What is the difference between arrow (→) and colon (:) case labels in switch?","**Arrow labels** (`case X ->`) execute a single expression, block, or\n`throw` and **do not fall through** to the next case.\n\n**Colon labels** (`case X:`) are the traditional style — they fall through\nto the next case unless a `break` or `return` stops them.\n\n```java\n\u002F\u002F Arrow — no fall-through, cleaner\nint result = switch (x) {\n    case 1 -> 10;\n    case 2 -> 20;\n    default -> 0;\n};\n\n\u002F\u002F Colon — falls through; needs break\nswitch (x) {\n    case 1:\n    case 2:\n        System.out.println(\"1 or 2\"); \u002F\u002F fall-through intentional here\n        break;\n    default:\n        System.out.println(\"other\");\n}\n```\n\nArrow labels can also use a block with `yield` to produce a value:\n```java\nint r = switch (x) {\n    case 1 -> 10;\n    default -> { int v = compute(x); yield v * 2; }\n};\n```\n\n**Rule of thumb:** use arrow labels for new switch expressions;\nuse colon labels only when intentional fall-through is needed.\n",{"id":2613,"difficulty":113,"q":2614,"a":2615},"yield-keyword","What does the yield keyword do in a switch expression?","`yield` returns a value from a **block** arm of a switch expression,\nsimilar to `return` in a method but scoped to the switch:\n\n```java\nint fee = switch (membership) {\n    case \"gold\"   -> 0;\n    case \"silver\" -> 5;\n    default -> {\n        int base = 10;\n        int extra = membership.length();\n        yield base + extra;   \u002F\u002F produces the value of this arm\n    }\n};\n```\n\n`yield` is only valid inside a switch expression block arm; in arrow\narms the expression result is yielded implicitly.\n\n**Rule of thumb:** use `yield` only in block arms (`{ ... }`); single-\nexpression arms use the expression value automatically.\n",{"id":2617,"difficulty":105,"q":2618,"a":2619},"type-pattern-in-switch","What is a type pattern in a switch expression?","A **type pattern** (Java 21, JEP 441) lets a `switch` match on the\nruntime type of the selector and bind the matched object to a variable in\none step — eliminating the cast:\n\n```java\nObject obj = getObject();\n\nString desc = switch (obj) {\n    case Integer i  -> \"int: \" + i;\n    case String s   -> \"string: \" + s;\n    case null       -> \"null\";\n    default         -> \"other: \" + obj.getClass().getSimpleName();\n};\n```\n\nCompare the old way:\n```java\n\u002F\u002F Before type patterns:\nif (obj instanceof Integer) {\n    Integer i = (Integer) obj;  \u002F\u002F explicit cast\n    ...\n}\n```\n\n**Rule of thumb:** type patterns in switch are cleaner than chains of\n`if\u002Felse instanceof` + cast — and they're exhaustiveness-checked when\nthe selector is a sealed type.\n",{"id":2621,"difficulty":105,"q":2622,"a":2623},"guarded-patterns","What are guarded patterns (when clause) in switch?","A **guarded pattern** adds a boolean condition (`when`) to a type pattern\ncase, allowing fine-grained filtering without a nested `if`:\n\n```java\nObject obj = getValue();\n\nString result = switch (obj) {\n    case Integer i when i \u003C 0   -> \"negative int: \" + i;\n    case Integer i when i == 0  -> \"zero\";\n    case Integer i              -> \"positive int: \" + i;\n    case String s when s.isEmpty() -> \"empty string\";\n    case String s               -> \"string: \" + s;\n    default                     -> \"other\";\n};\n```\n\nThe `when` clause is evaluated only if the type pattern matches. Cases\nare evaluated **top-to-bottom**; more specific guards should come first.\n\n**Rule of thumb:** use `when` guards to avoid nested `if` inside a case\nblock; order from most to least specific so the right case is selected first.\n",{"id":2625,"difficulty":105,"q":2626,"a":2627},"exhaustiveness-sealed","How does pattern matching enforce exhaustiveness for sealed types?","When the switch selector is a **sealed type**, the compiler verifies that\nevery permitted subtype is covered by at least one case. If you add a new\npermitted subtype without updating the switch, you get a **compile error**:\n\n```java\nsealed interface Shape permits Circle, Square {}\nrecord Circle(double r) implements Shape {}\nrecord Square(double s) implements Shape {}\n\ndouble area(Shape shape) {\n    return switch (shape) {    \u002F\u002F exhaustive — compiler verified\n        case Circle c -> Math.PI * c.r() * c.r();\n        case Square s -> s.s() * s.s();\n    };\n    \u002F\u002F If we add 'Triangle' to Shape's permits, this becomes a compile error\n}\n```\n\nFor non-sealed types or `Object`, a `default` case (or a `case null,\ndefault`) is required to make the switch exhaustive.\n\n**Rule of thumb:** sealed type + switch = compiler-enforced exhaustiveness;\n`default` is your escape hatch for open hierarchies.\n",{"id":2629,"difficulty":105,"q":2630,"a":2631},"null-in-switch","How does switch handle null in Java 21?","Traditionally, passing `null` to a `switch` statement throws a\n`NullPointerException`. Java 21 allows explicit `case null` to handle it:\n\n```java\nString s = getString(); \u002F\u002F might be null\n\nswitch (s) {\n    case null           -> System.out.println(\"null!\");\n    case \"hello\"        -> System.out.println(\"hello\");\n    default             -> System.out.println(\"other: \" + s);\n}\n```\n\nYou can also combine null with default: `case null, default ->`.\nIf no `case null` is present, `null` still throws `NullPointerException`\nto preserve backward compatibility.\n\n**Rule of thumb:** add `case null` explicitly in pattern-matching switches\nwherever `null` is a possible input; don't rely on NPE as flow control.\n",{"id":2633,"difficulty":105,"q":2634,"a":2635},"record-deconstruction-switch","How do record deconstruction patterns work in switch?","**Record patterns** (Java 21, JEP 440) destructure a record's components\ndirectly in a `case`, binding them to variables without explicit accessor\ncalls:\n\n```java\nsealed interface Expr permits Num, Add {}\nrecord Num(int v)           implements Expr {}\nrecord Add(Expr l, Expr r)  implements Expr {}\n\nint eval(Expr e) {\n    return switch (e) {\n        case Num(int v)           -> v;\n        case Add(Expr l, Expr r)  -> eval(l) + eval(r);\n    };\n}\n```\n\nNested deconstruction also works — you can deconstruct components that\nare themselves records:\n\n```java\nrecord Point(int x, int y) {}\nrecord Segment(Point start, Point end) {}\n\nString describe(Segment seg) {\n    return switch (seg) {\n        case Segment(Point(int x1, int y1), Point(int x2, int y2))\n            -> \"(%d,%d)→(%d,%d)\".formatted(x1, y1, x2, y2);\n    };\n}\n```\n\n**Rule of thumb:** record deconstruction removes the ceremony of\n`instanceof` + cast + accessor chain — especially powerful for recursive\ndata types like ASTs.\n",{"id":2637,"difficulty":113,"q":2638,"a":2639},"pattern-matching-instanceof","What is pattern matching for instanceof and how does it relate to switch patterns?","**Pattern matching for `instanceof`** (Java 16, JEP 394) is the simpler\nsibling: it binds a variable in a single `instanceof` check:\n\n```java\nObject obj = getObject();\n\n\u002F\u002F Old way:\nif (obj instanceof String) {\n    String s = (String) obj;\n    System.out.println(s.toUpperCase());\n}\n\n\u002F\u002F Pattern matching (Java 16+):\nif (obj instanceof String s) {\n    System.out.println(s.toUpperCase()); \u002F\u002F s is in scope here\n}\n```\n\n`instanceof` patterns also work in logical expressions:\n```java\nif (obj instanceof String s && s.length() > 5) { ... }\n```\n\nSwitch type patterns (Java 21) extend the same concept to multi-way\ndispatch. Both are part of the same **pattern matching** feature family.\n\n**Rule of thumb:** use `instanceof` patterns for single-type checks;\nuse switch type patterns for multi-way dispatch over several types.\n",{"id":2641,"difficulty":126,"q":2642,"a":2643},"dominance-ordering","What is dominance in switch pattern matching and how do you order cases?","A type pattern `case A a` **dominates** `case B b` if every `B` is also\nan `A` (i.e., `B` is a subtype of `A`). The compiler rejects a switch\nwhere a more general pattern appears before a more specific one, because\nthe specific case would be **unreachable**:\n\n```java\nObject obj = ...;\n\n\u002F\u002F Compile error — 'case Object o' dominates 'case String s':\nswitch (obj) {\n    case Object o -> System.out.println(\"object\");\n    case String s -> System.out.println(\"string\"); \u002F\u002F unreachable!\n}\n\n\u002F\u002F Correct — most specific first:\nswitch (obj) {\n    case String s  -> System.out.println(\"string\");\n    case Integer i -> System.out.println(\"int\");\n    default        -> System.out.println(\"other\");\n}\n```\n\n**Rule of thumb:** order cases from most specific to most general;\nthe compiler will reject unreachable cases due to dominance.\n",{"id":2645,"difficulty":113,"q":2646,"a":2647},"switch-strings-and-primitives","What types can be used as switch selectors in modern Java?","Switch selectors have expanded across Java versions:\n\n| Java version | Selector types |\n|---|---|\n| Traditional | `byte`, `short`, `char`, `int`, their wrappers, `String`, enums |\n| Java 14 (switch expressions) | Same types, new syntax |\n| Java 21 (pattern matching) | Any reference type (`Object`, interfaces, classes) |\n\n```java\n\u002F\u002F Java 21 — Object selector with type patterns:\nObject val = getValue();\nString desc = switch (val) {\n    case Integer i -> \"int \" + i;\n    case Long l    -> \"long \" + l;\n    case String s  -> \"str \" + s;\n    case null      -> \"null\";\n    default        -> \"?\" + val;\n};\n```\n\nNote: primitive `long`, `float`, `double` are **not** yet valid selectors\n(targeted for a future release via JEP 455 in Java 23 preview).\n\n**Rule of thumb:** in Java 21+ you can switch on any object — the old\nrestriction to `int`\u002F`String`\u002F`enum` is lifted for pattern matching.\n",{"id":2649,"difficulty":113,"q":2650,"a":2651},"switch-multiple-labels","How do you match multiple values in a single switch case?","Both traditional and modern switch support **multiple labels per case**\nseparated by commas:\n\n```java\nint numLetters = switch (day) {\n    case MONDAY, FRIDAY, SUNDAY -> 6;\n    case TUESDAY               -> 7;\n    case THURSDAY, SATURDAY    -> 8;\n    case WEDNESDAY             -> 9;\n};\n```\n\nThis is cleaner than the old fall-through trick with colon syntax. In\npattern-matching switches, combining type patterns with multiple labels\nis limited — each type pattern must be a separate case.\n\n**Rule of thumb:** use comma-separated labels for grouping equivalent\nenum\u002Fconstant cases; keep type pattern cases separate.\n",{"id":2653,"difficulty":113,"q":2654,"a":2655},"when-to-use-switch-expression","When should you prefer a switch expression over an if-else chain?","Prefer a **switch expression** when:\n- You're selecting one of several branches based on a single value.\n- The result is a value assigned to a variable or returned.\n- You want the compiler to enforce exhaustiveness.\n- The type is an enum, sealed type, or set of known constants.\n\nPrefer **if-else** when:\n- Conditions are complex boolean expressions (not just equality).\n- You're testing different variables in each branch.\n- Only one or two branches exist (switch adds noise for binary choices).\n\n```java\n\u002F\u002F Good switch expression — enum selector, value result, exhaustive\ndouble discount = switch (tier) {\n    case GOLD   -> 0.20;\n    case SILVER -> 0.10;\n    case BRONZE -> 0.05;\n};\n\n\u002F\u002F Keep as if-else — unrelated conditions\nif (user.isAdmin() && request.getSize() > MAX) { ... }\nelse if (ctx.isReadOnly()) { ... }\n```\n\n**Rule of thumb:** switch expressions shine on enums and sealed types;\nif-else is better for unrelated conditions or complex predicates.\n",{"id":2657,"difficulty":105,"q":2658,"a":2659},"switch-vs-polymorphism","When should you use switch pattern matching versus polymorphism?","This is the classic **tell-don't-ask** debate:\n\n**Polymorphism** is better when:\n- You expect third parties to add new subtypes (open hierarchy).\n- The operation is fundamental to the type and belongs in the class.\n- You have many operations that all need the same subtype-specific behaviour.\n\n**Switch pattern matching** is better when:\n- You own all the subtypes (closed\u002Fsealed hierarchy).\n- The operation is external to the type (e.g., serialisation, rendering).\n- You want compile-time exhaustiveness checking.\n\n```java\n\u002F\u002F Polymorphism — Shape knows how to compute its own area\ninterface Shape { double area(); }\n\n\u002F\u002F Switch — external function; exhaustiveness verified by compiler\ndouble area(Shape s) {\n    return switch (s) {\n        case Circle c    -> Math.PI * c.r() * c.r();\n        case Rectangle r -> r.w() * r.h();\n    };\n}\n```\n\n**Rule of thumb:** sealed types + switch for operations owned by the caller;\npolymorphism for behaviour the type itself should own.\n",{"description":103},"Java switch pattern matching interview questions — switch expressions vs statements, type patterns, guarded patterns, record deconstruction, exhaustiveness, null handling in switch, arrow vs colon syntax, and pattern matching for instanceof.","java\u002Fmodern-java\u002Fswitch-pattern-matching","GAwpTTmi-7w5m78Th5Ygzha-X_UEF8pxOyLiB6lfN2w",{"id":2665,"title":2666,"body":2667,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":2671,"navigation":108,"order":38,"path":2672,"questions":2673,"questionsCount":980,"related":250,"seo":2734,"seoDescription":2735,"stem":2736,"subtopic":2666,"topic":28,"topicSlug":30,"updated":1068,"__hash__":2737},"qa\u002Fjava\u002Foop\u002Fpolymorphism.md","Polymorphism",{"type":100,"value":2668,"toc":2669},[],{"title":103,"searchDepth":29,"depth":29,"links":2670},[],{},"\u002Fjava\u002Foop\u002Fpolymorphism",[2674,2678,2682,2686,2690,2694,2698,2702,2706,2710,2714,2718,2722,2726,2730],{"id":2675,"difficulty":105,"q":2676,"a":2677},"polymorphism","What is polymorphism and what are its forms?","Polymorphism = \"many forms.\" Java has two kinds:\n\n- **Runtime (dynamic) polymorphism** — method **overriding**. The JVM picks the\n  method based on the *actual object* at runtime (dynamic dispatch).\n- **Compile-time (static) polymorphism** — method **overloading**. The compiler\n  picks the method based on the *declared argument types*.\n\n```java\nAnimal a = new Dog();\na.sound();   \u002F\u002F runtime: Dog's override is chosen\n\nprint(5);    \u002F\u002F compile-time: print(int)\nprint(\"hi\"); \u002F\u002F compile-time: print(String)\n```\n\n\"Polymorphism\" in interviews usually means the runtime kind — the engine behind\n`List\u003CShape>` calling each shape's own `area()`.\n",{"id":2679,"difficulty":105,"q":2680,"a":2681},"overloading-vs-overriding","What is the difference between overloading and overriding?","| | Overloading | Overriding |\n| --- | --- | --- |\n| What | Same name, **different parameters** | Subclass **replaces** a superclass method |\n| Signature | Must differ (type\u002Fcount) | Must be **identical** |\n| Bound | **Compile time** (static) | **Run time** (dynamic) |\n| Return type | Can differ | Same or covariant |\n\n```java\nclass Calc {\n  int add(int a, int b) { return a + b; }          \u002F\u002F overload 1\n  double add(double a, double b) { return a + b; }  \u002F\u002F overload 2\n}\nclass Base { void greet() { } }\nclass Sub extends Base { @Override void greet() { } } \u002F\u002F override\n```\n\nOverloading is about offering variations of an operation; overriding is about\nspecializing inherited behavior. Use `@Override` so the compiler verifies you\nactually overrode (and didn't accidentally overload).\n",{"id":2683,"difficulty":105,"q":2684,"a":2685},"overriding-rules","What are the rules for overriding a method?","To override (not overload), the subclass method must:\n\n1. Have the **same name and parameter list** (signature).\n2. Have the **same or a covariant (narrower)** return type.\n3. Have **the same or wider access** (you can't make it more restrictive).\n4. Throw **the same or fewer\u002Fnarrower** checked exceptions.\n\n```java\nclass Base {\n  protected Number make() throws IOException { return 1; }\n}\nclass Sub extends Base {\n  @Override public Integer make() { return 2; } \u002F\u002F wider access, covariant, no checked throws — OK\n}\n```\n\n`private`, `static`, and `final` methods **can't** be overridden. **Rule of\nthumb:** always add `@Override` — the compiler then rejects anything that's\nsecretly an overload or a typo'd signature.\n",{"id":2687,"difficulty":105,"q":2688,"a":2689},"dynamic-dispatch","What is dynamic method dispatch?","Dynamic (virtual) dispatch is how the JVM decides, **at runtime**, which\noverridden method to call — based on the **actual object's class**, not the\nreference type. It's the mechanism that makes runtime polymorphism work.\n\n```java\nclass Shape { double area() { return 0; } }\nclass Circle extends Shape { double area() { return Math.PI; } }\n\nShape s = new Circle();\ns.area();    \u002F\u002F Circle.area() — chosen by the object, not the Shape reference\n```\n\nEach object carries a pointer to its class's method table (vtable); the call\nlooks up the override there. **Rule of thumb:** instance methods are virtual by\ndefault in Java — the runtime type wins.\n",{"id":2691,"difficulty":105,"q":2692,"a":2693},"runtime-vs-compiletime-poly","How does compile-time polymorphism differ from runtime polymorphism?","- **Compile-time (static) polymorphism** = **overloading**. The compiler resolves\n  the call from the **declared argument types**; fixed before the program runs.\n- **Runtime (dynamic) polymorphism** = **overriding**. The JVM resolves the call\n  from the **actual object** during execution.\n\n```java\nvoid print(int x) { }\nvoid print(Object o) { }\nprint(5);            \u002F\u002F compile-time: print(int) chosen by arg type\n\nAnimal a = pickAnimal();\na.sound();           \u002F\u002F runtime: depends on what pickAnimal() returned\n```\n\n**Rule of thumb:** overloading is decided by *what the compiler sees* (reference\ntypes); overriding by *what actually exists* (object type) at runtime.\n",{"id":2695,"difficulty":126,"q":2696,"a":2697},"static-vs-dynamic-binding","What is the difference between static and dynamic binding?","**Static binding** is resolved by the compiler from the **declared type** —\nused for `static`, `private`, `final`, and overloaded methods, plus fields.\n**Dynamic binding** is resolved at runtime from the **actual object type** —\nused for overridden instance methods (virtual dispatch).\n\n```java\nclass A { static void s() { } void v() { } int f = 1; }\nclass B extends A { static void s() { } @Override void v() { } int f = 2; }\n\nA x = new B();\nx.v();   \u002F\u002F B.v()  — dynamic binding (overridden)\nx.s();   \u002F\u002F A.s()  — static binding (hidden, by declared type)\nx.f;     \u002F\u002F 1      — fields are static-bound, not polymorphic\n```\n\nKey insight: **fields and static methods are *hidden*, not overridden** — they\nbind to the declared type, which is a classic trick question.\n",{"id":2699,"difficulty":126,"q":2700,"a":2701},"method-hiding","What is method hiding and how does it differ from overriding?","When a subclass declares a `static` method with the same signature as a parent\n`static` method, it **hides** rather than overrides it. The version called\ndepends on the **declared (compile-time) type**, not the runtime object — the\nopposite of overriding.\n\n```java\nclass A { static String who() { return \"A\"; } }\nclass B extends A { static String who() { return \"B\"; } }\n\nA ref = new B();\nref.who();   \u002F\u002F \"A\"  — static method, resolved by declared type (hiding)\n\u002F\u002F If who() were an instance method, this would be \"B\" (overriding)\n```\n\nBecause of this confusion, call static methods on the **class** (`A.who()`),\nnever through an instance reference.\n",{"id":2703,"difficulty":126,"q":2704,"a":2705},"covariant-return","What is a covariant return type?","When overriding, the subclass method may return a **subtype** of the\nsuperclass method's return type — a covariant return. It lets overrides return\nmore specific types without a cast.\n\n```java\nclass Animal { Animal reproduce() { return new Animal(); } }\nclass Dog extends Animal {\n  @Override Dog reproduce() { return new Dog(); } \u002F\u002F narrower return — legal\n}\nDog puppy = new Dog().reproduce(); \u002F\u002F no cast needed\n```\n\nCommon in builder patterns and `clone()` overrides. (Parameters, by contrast,\nare *not* covariant — changing a parameter type makes it an overload, not an\noverride.)\n",{"id":2707,"difficulty":105,"q":2708,"a":2709},"can-override-static","Can you override a static, final or private method?","No to all three, for different reasons:\n\n- **`static`** — bound to the class, not the instance; redeclaring it in a\n  subclass **hides** it (resolved by declared type), it isn't overridden.\n- **`final`** — explicitly sealed against overriding; won't compile if you try.\n- **`private`** — not visible to the subclass at all, so a same-named method is a\n  brand-new, unrelated method.\n\n```java\nclass A {\n  static void s() { }\n  final void f() { }\n  private void p() { }\n}\nclass B extends A {\n  static void s() { }    \u002F\u002F hides, not overrides\n  \u002F\u002F void f() { }        \u002F\u002F ERROR — can't override final\n  void p() { }           \u002F\u002F new method — A.p() is invisible here\n}\n```\n\n**Rule of thumb:** only **inherited, visible, non-final instance** methods are\ntruly overridable.\n",{"id":2711,"difficulty":126,"q":2712,"a":2713},"overload-resolution","How does the compiler resolve which overload to call?","The compiler picks the **most specific** applicable overload using the\n**compile-time (declared) argument types**, in phases: exact\u002Fwidening match\nfirst, then autoboxing, then varargs — preferring the path that needs the least\nconversion.\n\n```java\nvoid m(Object o) { }\nvoid m(Integer i) { }\nvoid m(int... xs) { }\n\nm(5);          \u002F\u002F m(int...)? No — m(Integer) via boxing beats varargs?\n               \u002F\u002F Actually: widening\u002Fboxing phase -> m(Integer) chosen over varargs\nInteger n = null;\nm(n);          \u002F\u002F m(Integer) — reference match, no boxing\n```\n\nBecause it uses **static types**, `m((Object) myInteger)` calls `m(Object)` even\nif the value is an `Integer`. **Rule of thumb:** overloads are resolved by the\n*reference type you pass*, not the runtime value — avoid ambiguous overloads.\n",{"id":2715,"difficulty":105,"q":2716,"a":2717},"polymorphism-collections","How does polymorphism enable programming to an interface?","By declaring variables and parameters as the **interface\u002Fsupertype**, your code\nworks with *any* implementation — the runtime calls the actual object's\nmethods. This decouples callers from concrete classes.\n\n```java\nvoid process(List\u003CString> items) { }   \u002F\u002F accepts ArrayList, LinkedList, List.of...\nList\u003CString> list = new ArrayList\u003C>();  \u002F\u002F swap impl freely\n\u002F\u002F list = new LinkedList\u003C>();           \u002F\u002F no caller changes needed\n```\n\n\"Program to an interface, not an implementation\" — depend on `List`, `Map`,\n`Collection`, not `ArrayList`\u002F`HashMap`. It makes code testable (inject fakes)\nand flexible (change implementations without ripple effects).\n",{"id":2719,"difficulty":113,"q":2720,"a":2721},"super-in-override","How do you call the parent's version of an overridden method?","Use `super.method()`. Inside an override, `super` skips the current class's\nversion and invokes the **immediate superclass's** implementation — useful to\n*extend* rather than *replace* behavior.\n\n```java\nclass Logger { void log(String m) { System.out.println(m); } }\nclass TimestampLogger extends Logger {\n  @Override void log(String m) {\n    super.log(java.time.Instant.now() + \" \" + m);  \u002F\u002F reuse + augment\n  }\n}\n```\n\nYou can only reach **one level up** — there's no `super.super`. **Rule of thumb:**\n`super.method()` is the \"decorate the inherited behavior\" tool.\n",{"id":2723,"difficulty":105,"q":2724,"a":2725},"abstract-polymorphism","How do abstract methods support polymorphism?","An **abstract method** declares a contract with no body; each concrete subclass\n*must* provide an implementation. Code calling the method through the abstract\ntype gets each subclass's behavior via dynamic dispatch — polymorphism with a\ncompiler-enforced contract.\n\n```java\nabstract class Shape { abstract double area(); }\nclass Circle extends Shape { double area() { return Math.PI * r * r; } double r = 1; }\nclass Square extends Shape { double area() { return s * s; } double s = 2; }\n\nfor (Shape sh : List.of(new Circle(), new Square()))\n  sh.area();   \u002F\u002F each computes its own — caller doesn't care which\n```\n\n**Rule of thumb:** abstract methods are \"polymorphism you can't forget to\nimplement\" — the compiler stops you from leaving a hole.\n",{"id":2727,"difficulty":105,"q":2728,"a":2729},"why-override-equals-poly","Why is calling an overridable method from a constructor dangerous?","During construction the **subclass override runs before the subclass's fields are\ninitialized**, because the superclass constructor executes first. The override\nthen sees default (`null`\u002F`0`) values.\n\n```java\nclass Base {\n  Base() { init(); }            \u002F\u002F calls the override...\n  void init() { }\n}\nclass Sub extends Base {\n  String name = \"set\";\n  @Override void init() { System.out.println(name); } \u002F\u002F prints null!\n}\nnew Sub();   \u002F\u002F null — name not assigned yet\n```\n\nThis is dynamic dispatch biting you mid-construction. **Rule of thumb:** never\ncall overridable (non-`final`, non-`private`) methods from a constructor — make\nsuch helpers `final` or `private`.\n",{"id":2731,"difficulty":113,"q":2732,"a":2733},"polymorphism-benefits","What practical benefits does polymorphism give you?","- **Extensibility** — add a new subtype without touching code that uses the\n  supertype (open\u002Fclosed principle).\n- **Decoupling** — callers depend on an abstraction, so implementations swap\n  freely (and fakes\u002Fmocks slot in for tests).\n- **Cleaner code** — replaces `if\u002Felse`\u002F`switch` on type with one virtual call.\n\n```java\n\u002F\u002F No type-switching — each shape knows its own area\ndouble total = 0;\nfor (Shape s : shapes) total += s.area();\n```\n\n**Rule of thumb:** when you see a `switch` on an object's \"kind,\" polymorphism\nusually expresses it better — give each kind its own method.\n",{"description":103},"Java polymorphism interview questions — overloading vs overriding, runtime vs compile-time polymorphism, dynamic dispatch, overriding rules, covariant returns, method hiding, static\u002Fdynamic binding and programming to an interface.","java\u002Foop\u002Fpolymorphism","7o2uqyC5UrgJanCk1Qm7O3uwi92NkXboNuX1-MmHgdE",{"id":2739,"title":2740,"body":2741,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":2745,"navigation":108,"order":38,"path":2746,"questions":2747,"questionsCount":805,"related":250,"seo":2836,"seoDescription":2837,"stem":2838,"subtopic":2839,"topic":55,"topicSlug":56,"updated":809,"__hash__":2840},"qa\u002Fjava\u002Fstreams-functional\u002Fcollectors-grouping.md","Collectors Grouping",{"type":100,"value":2742,"toc":2743},[],{"title":103,"searchDepth":29,"depth":29,"links":2744},[],{},"\u002Fjava\u002Fstreams-functional\u002Fcollectors-grouping",[2748,2752,2756,2760,2764,2768,2772,2776,2780,2784,2788,2792,2796,2800,2804,2808,2812,2816,2820,2824,2828,2832],{"id":2749,"difficulty":105,"q":2750,"a":2751},"collect-overview","What does the collect() terminal operation do?","`collect` is a **mutable reduction** terminal operation: it folds the stream's\nelements into a **mutable result container** (a `List`, `Map`, `StringBuilder`,\netc.) by repeatedly accumulating into it. It takes a **`Collector`**, and the\n`java.util.stream.Collectors` class is a factory of ready-made ones.\n\n```java\nList\u003CString> upper = names.stream()\n    .map(String::toUpperCase)\n    .collect(Collectors.toList());\n```\n\nUnlike `reduce`, which combines **immutable** values, `collect` mutates a\ncontainer in place, which is far more efficient for building collections and\nstrings. Reach for the `Collectors` factory first — only write a custom\ncollector when nothing there fits.\n",{"id":2753,"difficulty":126,"q":2754,"a":2755},"collector-anatomy","What are the four components of a Collector?","A `Collector\u003CT, A, R>` is defined by **four functions** (`T` = input element,\n`A` = mutable accumulation type, `R` = final result):\n\n| Component | Role |\n| --------- | ---- |\n| **supplier** | creates a new empty mutable container (`A`) |\n| **accumulator** | folds one element into the container |\n| **combiner** | merges two partial containers (used in parallel) |\n| **finisher** | transforms the container `A` into the result `R` |\n\n```java\n\u002F\u002F toList conceptually: supplier=ArrayList::new,\n\u002F\u002F accumulator=List::add, combiner=addAll, finisher=identity\n```\n\nA fifth piece, **characteristics**, hints at optimizations. The **combiner**\nis what makes a collector parallel-safe; the **finisher** is skipped entirely\nwhen the container already *is* the result (`IDENTITY_FINISH`).\n",{"id":2757,"difficulty":113,"q":2758,"a":2759},"to-list-set-collection","How do toList, toSet and toCollection differ?","All three gather elements into a collection, differing in the container:\n\n- **`toList()`** — accumulates into a `List` (an `ArrayList` in practice).\n- **`toSet()`** — accumulates into a `Set` (a `HashSet`), dropping duplicates,\n  with no order guarantee.\n- **`toCollection(supplier)`** — accumulates into **whatever collection** you\n  supply, when you need a specific type.\n\n```java\nList\u003CString> list = s.collect(Collectors.toList());\nSet\u003CString>  set  = s.collect(Collectors.toSet());\nTreeSet\u003CString> sorted =\n    s.collect(Collectors.toCollection(TreeSet::new)); \u002F\u002F sorted, no dups\n```\n\nUse `toCollection` when the default type won't do — e.g. a `TreeSet` for\nordering or a `LinkedList` for insertion semantics.\n",{"id":2761,"difficulty":105,"q":2762,"a":2763},"collectors-tolist-vs-stream-tolist","What is the difference between Collectors.toList() and Stream.toList()?","Both produce a `List`, but the **mutability and null handling** differ:\n\n| | `collect(Collectors.toList())` | `stream.toList()` (Java 16+) |\n| - | - | - |\n| Mutability | **modifiable** (`ArrayList`) | **unmodifiable** |\n| Allows `null` | yes | yes |\n| Conciseness | verbose | one method |\n\n```java\nList\u003CInteger> a = nums.stream().collect(Collectors.toList());\na.add(99);                      \u002F\u002F OK — mutable\n\nList\u003CInteger> b = nums.stream().toList();\nb.add(99);                      \u002F\u002F UnsupportedOperationException\n```\n\nPrefer the newer `stream().toList()` for read-only results; it's shorter and\nits immutability prevents accidental mutation. Use `Collectors.toList()` only\nwhen you genuinely need to modify the result afterward.\n",{"id":2765,"difficulty":105,"q":2766,"a":2767},"to-unmodifiable","How do you collect into an unmodifiable collection?","Java 10 added **`toUnmodifiableList`**, **`toUnmodifiableSet`** and\n**`toUnmodifiableMap`**, which return collections that throw\n`UnsupportedOperationException` on any mutation. They also **reject `null`**\nelements (throwing `NullPointerException`).\n\n```java\nList\u003CString> ro = names.stream()\n    .filter(n -> n.length() > 3)\n    .collect(Collectors.toUnmodifiableList());\nro.clear(); \u002F\u002F UnsupportedOperationException\n```\n\nThese are the collector equivalents of `List.of`\u002F`Set.of`\u002F`Map.of`. Since\nJava 16 you can also just use `stream().toList()` for an unmodifiable `List`.\n",{"id":2769,"difficulty":105,"q":2770,"a":2771},"to-map-basics","How does Collectors.toMap work?","`toMap` builds a `Map` from each element using a **key mapper** and a **value\nmapper** — two functions that derive the key and value from each element.\n\n```java\nMap\u003CString, Integer> byName = people.stream()\n    .collect(Collectors.toMap(\n        Person::name,        \u002F\u002F key mapper\n        Person::age));       \u002F\u002F value mapper\n```\n\nBy default the result is a `HashMap`. The catch interviewers probe is **duplicate\nkeys**: if two elements map to the same key, the two-argument `toMap` throws an\n**`IllegalStateException`** (\"Duplicate key\") — you must supply a merge function\nto resolve collisions.\n",{"id":2773,"difficulty":126,"q":2774,"a":2775},"to-map-merge","What is the merge function in toMap and when do you need it?","The **three-argument** `toMap` takes a **merge function** `(existing, new) ->\nresult` invoked whenever two elements produce the **same key**. Without it,\nduplicate keys throw `IllegalStateException`.\n\n```java\n\u002F\u002F two-arg: throws IllegalStateException on duplicate \"Bob\"\n\u002F\u002F three-arg: resolve the clash\nMap\u003CString, Integer> totals = orders.stream()\n    .collect(Collectors.toMap(\n        Order::customer,\n        Order::amount,\n        Integer::sum));        \u002F\u002F merge: add amounts for same customer\n```\n\nA **fourth** argument supplies the map type (e.g. `TreeMap::new`) for ordering\nor a specific implementation. Always provide a merge function when keys aren't\nguaranteed unique — it's the single most common `toMap` bug.\n",{"id":2777,"difficulty":105,"q":2778,"a":2779},"grouping-by-basics","What does Collectors.groupingBy do?","`groupingBy` takes a **classifier function** and partitions elements into a\n`Map\u003CK, List\u003CT>>` keyed by the classifier's result — every element with the\nsame key lands in the same list.\n\n```java\nMap\u003CDepartment, List\u003CEmployee>> byDept = employees.stream()\n    .collect(Collectors.groupingBy(Employee::department));\n```\n\nIt's the SQL `GROUP BY` of streams. The default value container is a `List` and\nthe default map is a `HashMap`. This single-argument form is the gateway — the\nreal power comes from adding a **downstream collector** to reshape each group.\n",{"id":2781,"difficulty":126,"q":2782,"a":2783},"grouping-by-downstream","What is a downstream collector in groupingBy?","The two-argument `groupingBy(classifier, downstream)` applies a **second\ncollector to each group** instead of just collecting elements into a list. This\nlets you count, sum, average, or otherwise reduce each bucket.\n\n```java\n\u002F\u002F count per department\nMap\u003CDept, Long> counts = emps.stream()\n    .collect(Collectors.groupingBy(Employee::dept, Collectors.counting()));\n\n\u002F\u002F sum of salaries per department\nMap\u003CDept, Integer> totals = emps.stream()\n    .collect(Collectors.groupingBy(Employee::dept,\n             Collectors.summingInt(Employee::salary)));\n```\n\nCommon downstreams: `counting`, `summingInt\u002FLong\u002FDouble`,\n`averagingInt\u002FDouble`, `mapping`, `toSet`, `joining`, `maxBy`\u002F`minBy`,\n`reducing`. Downstream collectors are the heart of expressive aggregation.\n",{"id":2785,"difficulty":126,"q":2786,"a":2787},"grouping-by-mapping","How do you transform group elements with the mapping downstream collector?","`Collectors.mapping(mapper, downstream)` applies a **transform** to each element\n*before* it reaches a further downstream collector — it adapts a collector to a\ndifferent input type. It's how you collect a **field** of each group member\nrather than the whole object.\n\n```java\n\u002F\u002F names of employees in each department\nMap\u003CDept, List\u003CString>> names = emps.stream()\n    .collect(Collectors.groupingBy(Employee::dept,\n             Collectors.mapping(Employee::name, Collectors.toList())));\n```\n\nThink of `mapping` as a `map()` embedded inside a collector. It pairs naturally\nwith `toList`, `toSet`, or `joining` to project group members.\n",{"id":2789,"difficulty":105,"q":2790,"a":2791},"grouping-by-counting","How do you count elements per group?","Combine `groupingBy` with the **`counting()`** downstream collector. `counting`\nreturns a `Long`, so the result is `Map\u003CK, Long>`.\n\n```java\nMap\u003CString, Long> wordFreq = words.stream()\n    .collect(Collectors.groupingBy(\n        Function.identity(),     \u002F\u002F group by the word itself\n        Collectors.counting())); \u002F\u002F count occurrences\n\u002F\u002F {\"the\"=4, \"cat\"=2, ...}\n```\n\n`Function.identity()` is the idiom for grouping elements **by themselves** — a\nfrequency map. This is the canonical \"count occurrences\" stream pattern.\n",{"id":2793,"difficulty":126,"q":2794,"a":2795},"nested-grouping","How do you do multi-level (nested) grouping?","Because the downstream of `groupingBy` can be **another `groupingBy`**, you\nnest them to build a multi-level map — exactly like a SQL `GROUP BY` on two\ncolumns.\n\n```java\n\u002F\u002F group by department, then by city within each department\nMap\u003CDept, Map\u003CString, List\u003CEmployee>>> nested = emps.stream()\n    .collect(Collectors.groupingBy(Employee::dept,\n             Collectors.groupingBy(Employee::city)));\n```\n\nYou can keep nesting or end with an aggregating downstream\n(`Map\u003CDept, Map\u003CString, Long>>` via `counting()`). The outer classifier forms\nthe first key level; each inner collector handles the next.\n",{"id":2797,"difficulty":105,"q":2798,"a":2799},"partitioning-by","What is partitioningBy and how does it differ from groupingBy?","`partitioningBy` splits a stream into **exactly two groups** using a\n**predicate**, returning a `Map\u003CBoolean, List\u003CT>>` with keys `true` and\n`false`. It's a specialized, optimized `groupingBy` for the boolean case.\n\n```java\nMap\u003CBoolean, List\u003CInteger>> parts = nums.stream()\n    .collect(Collectors.partitioningBy(n -> n % 2 == 0));\nparts.get(true);   \u002F\u002F evens\nparts.get(false);  \u002F\u002F odds\n```\n\nKey difference from `groupingBy`: the map **always contains both keys**, even\nwhen one partition is empty (`groupingBy` omits empty groups). It also accepts a\ndownstream collector: `partitioningBy(pred, counting())`.\n",{"id":2801,"difficulty":113,"q":2802,"a":2803},"joining","How does Collectors.joining work?","`joining` concatenates the stream's **`CharSequence`** elements into one\n`String`. It has three forms: no-arg (concatenate), one-arg (delimiter), and\nthree-arg (**delimiter, prefix, suffix**).\n\n```java\nString csv = names.stream()\n    .collect(Collectors.joining(\", \"));          \u002F\u002F \"Ann, Bob, Cy\"\n\nString list = names.stream()\n    .collect(Collectors.joining(\", \", \"[\", \"]\")); \u002F\u002F \"[Ann, Bob, Cy]\"\n```\n\nIt only accepts `CharSequence`, so `map(Object::toString)` first if your\nelements aren't strings. Internally it uses a `StringBuilder`, making it far\nmore efficient than reducing with `+`.\n",{"id":2805,"difficulty":105,"q":2806,"a":2807},"summing-averaging","What do the summing and averaging collectors return?","`summingInt\u002FLong\u002FDouble` apply a value-extracting function and **sum** the\nresults; `averagingInt\u002FLong\u002FDouble` compute the **mean**. Each takes a\n`ToIntFunction`-style mapper.\n\n```java\nint total = orders.stream()\n    .collect(Collectors.summingInt(Order::quantity));      \u002F\u002F sum -> int\u002Flong\n\ndouble avg = orders.stream()\n    .collect(Collectors.averagingInt(Order::quantity));    \u002F\u002F mean -> double\n```\n\nNote `summingInt` returns the primitive's boxed total, while **all\n`averaging*` variants return `Double`** (a mean is rarely integral). These shine\nas `groupingBy` downstreams for per-group totals and means.\n",{"id":2809,"difficulty":105,"q":2810,"a":2811},"summarizing-stats","What is summarizingInt and IntSummaryStatistics?","`summarizingInt\u002FLong\u002FDouble` compute **count, sum, min, max, and average in a\nsingle pass**, returning an `IntSummaryStatistics` (or `Long`\u002F`Double` variant)\nthat exposes all five.\n\n```java\nIntSummaryStatistics stats = employees.stream()\n    .collect(Collectors.summarizingInt(Employee::salary));\nstats.getCount();    \u002F\u002F 50\nstats.getSum();      \u002F\u002F 3_200_000\nstats.getMin();      \u002F\u002F 40_000\nstats.getMax();      \u002F\u002F 180_000\nstats.getAverage();  \u002F\u002F 64000.0\n```\n\nUse it instead of running several collectors when you need multiple statistics —\nit traverses the stream once. (`stream().mapToInt(...).summaryStatistics()` is\nthe equivalent without `collect`.)\n",{"id":2813,"difficulty":126,"q":2814,"a":2815},"reducing-collector","When would you use the reducing collector instead of Stream.reduce?","`Collectors.reducing` is a **collector-form** of reduction. Standalone it\nduplicates `Stream.reduce`, so its real purpose is being a **downstream\ncollector** inside `groupingBy`\u002F`partitioningBy`, where you can't drop to\n`Stream.reduce`.\n\n```java\n\u002F\u002F highest-paid employee per department\nMap\u003CDept, Optional\u003CEmployee>> top = emps.stream()\n    .collect(Collectors.groupingBy(Employee::dept,\n             Collectors.reducing(BinaryOperator.maxBy(\n                 Comparator.comparingInt(Employee::salary)))));\n```\n\nFor top-level reductions prefer `Stream.reduce` — it's clearer. Reach for\n`Collectors.reducing` (or the dedicated `maxBy`\u002F`minBy`) only as a downstream.\n",{"id":2817,"difficulty":126,"q":2818,"a":2819},"collecting-and-then","What does collectingAndThen do?","`collectingAndThen(downstream, finisher)` runs a collector, then applies a\n**finishing transformation** to its result. It's how you adapt a collector's\noutput — most commonly to wrap a collection as **unmodifiable** or to extract a\nvalue from an `Optional`.\n\n```java\nList\u003CString> immutable = names.stream()\n    .collect(Collectors.collectingAndThen(\n        Collectors.toList(),\n        Collections::unmodifiableList));\n\n\u002F\u002F unwrap the maxBy Optional per group\nMap\u003CDept, Employee> top = emps.stream()\n    .collect(Collectors.groupingBy(Employee::dept,\n             Collectors.collectingAndThen(\n                 Collectors.maxBy(Comparator.comparingInt(Employee::salary)),\n                 Optional::get)));\n```\n\nIt effectively bolts a custom **finisher** onto an existing collector without\nwriting one from scratch.\n",{"id":2821,"difficulty":126,"q":2822,"a":2823},"filtering-flatmapping","What are the filtering and flatMapping downstream collectors?","Added in **Java 9**, both are downstream collectors that solve a real problem:\nfiltering *before* the stream's `filter()` would silently drop empty groups.\n\n- **`filtering(predicate, downstream)`** — keeps only matching elements per\n  group, but **preserves the group key even if it becomes empty** (unlike a\n  pre-`filter`, which removes the whole bucket).\n- **`flatMapping(mapper, downstream)`** — flattens each element to a stream and\n  collects the results, the collector-level `flatMap`.\n\n```java\nMap\u003CDept, List\u003CEmployee>> highEarners = emps.stream()\n    .collect(Collectors.groupingBy(Employee::dept,\n             Collectors.filtering(e -> e.salary() > 100_000,\n                 Collectors.toList())));\n```\n\nUse `filtering` over an upstream `filter` whenever you need **every group key\npresent**, even with no surviving members.\n",{"id":2825,"difficulty":126,"q":2826,"a":2827},"teeing","What is the teeing collector?","`teeing` (Java 12) feeds each element to **two downstream collectors at once**,\nthen **merges their two results** with a `BiFunction`. It computes two\naggregates in a single pass.\n\n```java\n\u002F\u002F average = sum \u002F count, in one traversal\ndouble avg = nums.stream()\n    .collect(Collectors.teeing(\n        Collectors.summingDouble(n -> n),  \u002F\u002F result 1: sum\n        Collectors.counting(),             \u002F\u002F result 2: count\n        (sum, count) -> sum \u002F count));     \u002F\u002F merge\n```\n\nIt's ideal when two statistics depend on the same stream and you want to avoid\ncollecting to a list or streaming twice — e.g. min and max, or sum and count.\n",{"id":2829,"difficulty":126,"q":2830,"a":2831},"collector-characteristics","What are Collector characteristics?","Characteristics are **optimization hints** in a collector's `characteristics()`\nset that tell the stream pipeline what shortcuts are safe:\n\n- **`UNORDERED`** — the result doesn't depend on encounter order (e.g.\n  `toSet`), so the pipeline may reorder for speed.\n- **`CONCURRENT`** — the accumulator can be called on **one shared container\n  from multiple threads** (e.g. `groupingByConcurrent`), avoiding merges.\n- **`IDENTITY_FINISH`** — the finisher is the identity, so the container *is*\n  the result and the finisher step is **skipped**.\n\n```java\nCollectors.toList();  \u002F\u002F IDENTITY_FINISH\nCollectors.toSet();   \u002F\u002F UNORDERED, IDENTITY_FINISH\n```\n\nYou rarely set these directly — they matter mostly when writing a **custom**\ncollector or reasoning about parallel-stream performance.\n",{"id":2833,"difficulty":126,"q":2834,"a":2835},"custom-collector","How do you write a custom Collector with Collector.of?","Use **`Collector.of(supplier, accumulator, combiner, [finisher], characteristics...)`**,\npassing the four functions directly. The combiner is mandatory so the collector\nworks in parallel.\n\n```java\n\u002F\u002F a custom collector that joins names into a single uppercase CSV string\nCollector\u003CString, StringJoiner, String> upperCsv = Collector.of(\n    () -> new StringJoiner(\", \"),          \u002F\u002F supplier\n    (j, s) -> j.add(s.toUpperCase()),      \u002F\u002F accumulator\n    StringJoiner::merge,                   \u002F\u002F combiner\n    StringJoiner::toString);               \u002F\u002F finisher\n\nString result = names.stream().collect(upperCsv);\n```\n\nOmit the finisher when the container already is the result (an\n`IDENTITY_FINISH` collector). In practice, prefer composing existing\n`Collectors` (`mapping`, `collectingAndThen`, `teeing`) — write a fully custom\ncollector only when no combination fits.\n",{"description":103},"Java Collectors interview questions — collect and the Collectors factory, toList\u002FtoMap\u002FtoSet, groupingBy and partitioningBy, downstream collectors, joining, counting and summing, and writing a custom collector.","java\u002Fstreams-functional\u002Fcollectors-grouping","Collectors & Grouping","mR8XsxMuXt6DdH_AH7BfjvaWXSTrBmLJD6TV3cmT6Ls",{"id":2842,"title":2843,"body":2844,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":2848,"navigation":108,"order":47,"path":2849,"questions":2850,"questionsCount":904,"related":250,"seo":2933,"seoDescription":2934,"stem":2935,"subtopic":2936,"topic":46,"topicSlug":48,"updated":809,"__hash__":2937},"qa\u002Fjava\u002Fcollections\u002Fqueue-deque.md","Queue Deque",{"type":100,"value":2845,"toc":2846},[],{"title":103,"searchDepth":29,"depth":29,"links":2847},[],{},"\u002Fjava\u002Fcollections\u002Fqueue-deque",[2851,2855,2859,2863,2867,2871,2875,2879,2883,2886,2890,2894,2898,2902,2906,2910,2913,2917,2921,2925,2929],{"id":2852,"difficulty":113,"q":2853,"a":2854},"queue-interface","What is the Queue interface in Java?","`Queue\u003CE>` is a `Collection` that models a **FIFO** (first-in, first-out) order:\nelements are added at the **tail** and removed from the **head**. It extends\n`Collection` and is implemented by `LinkedList`, `ArrayDeque`,\n`PriorityQueue`, and the concurrent\u002Fblocking queues.\n\n```java\nQueue\u003CString> q = new LinkedList\u003C>();\nq.offer(\"a\");           \u002F\u002F enqueue at tail\nq.offer(\"b\");\nString head = q.poll(); \u002F\u002F dequeue from head -> \"a\"\nString next = q.peek(); \u002F\u002F look without removing -> \"b\"\n```\n\nNote that not every `Queue` is FIFO: `PriorityQueue` orders by priority and a\n`Deque` used as a stack is LIFO. The interface only guarantees the head is the\nelement returned by `peek`\u002F`poll` — the *ordering policy* is the\nimplementation's job.\n",{"id":2856,"difficulty":105,"q":2857,"a":2858},"queue-method-families","What are the two method families on Queue (throwing vs returning)?","Every core `Queue` operation comes in **two flavours**: one that **throws** an\nexception on failure and one that returns a **special value** (`false` or\n`null`). Use the throwing form when failure is a bug; use the returning form\nwhen emptiness\u002Ffullness is expected control flow.\n\n| Operation | Throws on failure | Returns special value |\n| --------- | ----------------- | --------------------- |\n| Insert | `add(e)` (throws `IllegalStateException` if full) | `offer(e)` (returns `false`) |\n| Remove head | `remove()` (throws `NoSuchElementException` if empty) | `poll()` (returns `null`) |\n| Examine head | `element()` (throws `NoSuchElementException` if empty) | `peek()` (returns `null`) |\n\n```java\nQueue\u003CInteger> q = new ArrayDeque\u003C>();\nq.poll();      \u002F\u002F null  — empty, no exception\nq.remove();    \u002F\u002F NoSuchElementException\n```\n\nThe returning forms (`offer`\u002F`poll`\u002F`peek`) are the safer default for\nbounded\u002Fconcurrent queues where failure is normal.\n",{"id":2860,"difficulty":105,"q":2861,"a":2862},"deque-interface","What is a Deque and how does it differ from a Queue?","`Deque\u003CE>` (\"double-ended queue\", pronounced \"deck\") lets you insert, remove,\nand examine at **both ends**. It extends `Queue`, so it can act as a plain FIFO\nqueue, but it adds a full set of `*First`\u002F`*Last` methods.\n\n```java\nDeque\u003CInteger> d = new ArrayDeque\u003C>();\nd.addFirst(1);   \u002F\u002F [1]\nd.addLast(2);    \u002F\u002F [1, 2]\nd.peekFirst();   \u002F\u002F 1\nd.peekLast();    \u002F\u002F 2\nd.pollFirst();   \u002F\u002F removes 1 -> [2]\n```\n\nBecause both ends are O(1), a `Deque` is the one structure that can serve as\n**either a FIFO queue or a LIFO stack** — which is exactly why modern code uses\nit in place of the legacy `Stack` class.\n",{"id":2864,"difficulty":105,"q":2865,"a":2866},"deque-method-table","What are the end-specific methods on Deque?","Each end has the same throwing-vs-returning split as `Queue`, doubled for first\nand last:\n\n| | First (head) throws | First returns | Last (tail) throws | Last returns |\n| --- | --- | --- | --- | --- |\n| Insert | `addFirst(e)` | `offerFirst(e)` | `addLast(e)` | `offerLast(e)` |\n| Remove | `removeFirst()` | `pollFirst()` | `removeLast()` | `pollLast()` |\n| Examine | `getFirst()` | `peekFirst()` | `getLast()` | `peekLast()` |\n\n```java\nDeque\u003CString> d = new ArrayDeque\u003C>();\nd.offerFirst(\"x\");   \u002F\u002F returns boolean, no throw\nd.peekLast();        \u002F\u002F null if empty, no throw\nd.getFirst();        \u002F\u002F NoSuchElementException if empty\n```\n\nThe throwing forms (`getFirst`, `removeLast`) fail loudly on an empty deque;\nthe returning forms (`peekFirst`, `pollLast`) give `null`. The inherited\n`Queue` methods map to the **first** end for removal and the **last** for\ninsertion.\n",{"id":2868,"difficulty":105,"q":2869,"a":2870},"deque-as-stack","How do you use a Deque as a stack?","`Deque` provides `push`, `pop`, and `peek`, which operate on the **head** as a\n**LIFO** stack: `push` is `addFirst`, `pop` is `removeFirst`, `peek` is\n`peekFirst`.\n\n```java\nDeque\u003CInteger> stack = new ArrayDeque\u003C>();\nstack.push(1);   \u002F\u002F [1]\nstack.push(2);   \u002F\u002F [2, 1]  (head is the top)\nstack.peek();    \u002F\u002F 2\nstack.pop();     \u002F\u002F 2  -> [1]\n```\n\nBoth ends are O(1), so this is a fast, clean stack. Note `pop`\u002F`peek` here\n**throw** `NoSuchElementException` on an empty deque (unlike `poll`\u002F`peekFirst`,\nwhich return `null`).\n",{"id":2872,"difficulty":105,"q":2873,"a":2874},"arraydeque-vs-stack","Why is ArrayDeque preferred over the legacy Stack class?","`java.util.Stack` extends `Vector`, which makes it **synchronized** on every\noperation (slow, and pointless for single-threaded use) and, worse, it exposes\n`Vector`'s index methods so you can `get(i)`\u002F`insertElementAt` into the middle —\nbreaking the stack abstraction. It also iterates **bottom-to-top**, the opposite\nof pop order.\n\n```java\n\u002F\u002F legacy — avoid\nStack\u003CInteger> old = new Stack\u003C>();\n\n\u002F\u002F modern stack — fast, clean LIFO\nDeque\u003CInteger> stack = new ArrayDeque\u003C>();\nstack.push(1);\nstack.pop();\n```\n\nThe Javadoc itself recommends `ArrayDeque` for stack use. It's unsynchronized\n(faster), has a tight contract (no random access), and iterates in the correct\norder.\n",{"id":2876,"difficulty":126,"q":2877,"a":2878},"arraydeque-vs-linkedlist","What is the difference between ArrayDeque and LinkedList as a Deque?","Both implement `Deque`, but the data structure underneath differs:\n\n| | `ArrayDeque` | `LinkedList` |\n| --- | --- | --- |\n| Backing store | resizable **circular array** | **doubly-linked** nodes |\n| Memory | one compact array | a node object + 2 pointers per element |\n| Cache locality | excellent (contiguous) | poor (scattered nodes) |\n| Allows `null` | **no** | yes |\n| Also implements | `Queue`, `Deque` | `List`, `Queue`, `Deque` |\n\n```java\nDeque\u003CInteger> fast = new ArrayDeque\u003C>();   \u002F\u002F prefer this\nDeque\u003CInteger> list = new LinkedList\u003C>();    \u002F\u002F only if you need List ops\n```\n\nFor pure queue\u002Fstack\u002Fdeque use, **`ArrayDeque` is faster** thanks to contiguous\nmemory and no per-element node allocation. Pick `LinkedList` only when you also\nneed `List` behavior (indexing, `ListIterator`) or must store `null`.\n",{"id":2880,"difficulty":105,"q":2881,"a":2882},"arraydeque-no-nulls","Why does ArrayDeque not allow null elements?","`ArrayDeque` (and most queues) **reject `null`** because `null` is the **sentinel\nvalue** returned by `poll`\u002F`peek` to mean \"the queue is empty.\" If a real `null`\nelement were allowed, you couldn't tell an empty queue from a queue whose head is\n`null`.\n\n```java\nDeque\u003CString> d = new ArrayDeque\u003C>();\nd.offer(null);   \u002F\u002F NullPointerException\nd.poll();        \u002F\u002F null only ever means \"empty\"\n```\n\nSo the no-null rule keeps the returning-value method family unambiguous.\n`LinkedList` predates this design and permits `null`, which is one more reason to\navoid it as a queue.\n",{"id":214,"difficulty":105,"q":2884,"a":2885},"What is a PriorityQueue and how is it ordered?","`PriorityQueue` is a `Queue` whose **head is always the smallest element** by\nthe ordering — not FIFO. It's backed by a **binary heap**, so `peek`\u002F`poll`\nreturn the minimum and `offer`\u002F`poll` are O(log n).\n\n```java\nPriorityQueue\u003CInteger> pq = new PriorityQueue\u003C>();\npq.offer(5);\npq.offer(1);\npq.offer(3);\npq.poll();   \u002F\u002F 1  — smallest first\npq.poll();   \u002F\u002F 3\n```\n\nOrdering comes from the elements' **`Comparable`** (natural order) or a\n**`Comparator`** passed to the constructor. It allows duplicates but, like other\nqueues, **not `null`**, and elements must be mutually comparable or you get a\n`ClassCastException`.\n",{"id":2887,"difficulty":105,"q":2888,"a":2889},"priorityqueue-comparator","How do you build a max-heap or custom-ordered PriorityQueue?","By default a `PriorityQueue` is a **min-heap** (natural order). Pass a\n`Comparator` to change the policy — `reverseOrder()` makes a max-heap, and a\nkey extractor orders by a field.\n\n```java\n\u002F\u002F max-heap: largest first\nPriorityQueue\u003CInteger> max = new PriorityQueue\u003C>(Comparator.reverseOrder());\nmax.offer(1); max.offer(9); max.offer(5);\nmax.poll();   \u002F\u002F 9\n\n\u002F\u002F order tasks by priority field\nPriorityQueue\u003CTask> tasks =\n    new PriorityQueue\u003C>(Comparator.comparingInt(Task::priority));\n```\n\nThe comparator is fixed at construction. For objects, supplying a `Comparator`\n(or implementing `Comparable`) is **mandatory** — without an ordering the heap\ncan't decide the head and throws `ClassCastException` on the first `offer`.\n",{"id":2891,"difficulty":126,"q":2892,"a":2893},"priorityqueue-iteration","Does iterating a PriorityQueue return elements in sorted order?","**No.** A `PriorityQueue`'s iterator (and `toString`) traverses the **internal\nheap array**, which is only *partially* ordered — the heap invariant guarantees\na parent precedes its children, not a fully sorted sequence. Only **`poll`**\nreturns elements in priority order.\n\n```java\nPriorityQueue\u003CInteger> pq = new PriorityQueue\u003C>(List.of(5, 1, 3, 2, 4));\nSystem.out.println(pq);            \u002F\u002F e.g. [1, 2, 3, 5, 4] — NOT sorted\n\nwhile (!pq.isEmpty())\n    System.out.print(pq.poll());   \u002F\u002F 12345 — sorted, by draining\n```\n\nTo get a sorted view you must repeatedly `poll` (which empties the queue) or\ncopy into a list and `sort` it. This \"the queue prints unsorted\" surprise is a\nclassic interview trap.\n",{"id":2895,"difficulty":105,"q":2896,"a":2897},"priorityqueue-complexity","What are the time complexities of PriorityQueue operations?","The binary heap gives:\n\n| Operation | Complexity |\n| --------- | ---------- |\n| `offer` \u002F `add` (insert) | O(log n) — sift up |\n| `poll` \u002F `remove()` (poll head) | O(log n) — sift down |\n| `peek` \u002F `element` (head) | O(1) |\n| `remove(Object)` \u002F `contains` | O(n) — linear scan |\n\n```java\nPriorityQueue\u003CInteger> pq = new PriorityQueue\u003C>();\npq.offer(7);     \u002F\u002F O(log n)\npq.peek();       \u002F\u002F O(1)\npq.remove(7);    \u002F\u002F O(n) — must search first\n```\n\nBuilding a heap from a known collection (the constructor that takes one) is\nO(n), better than n inserts. The O(n) `contains`\u002Farbitrary-`remove` is the cost\nto remember: heaps are great at \"give me the min,\" weak at \"find this element.\"\n",{"id":2899,"difficulty":105,"q":2900,"a":2901},"bounded-vs-unbounded","What is the difference between a bounded and an unbounded queue?","An **unbounded** queue grows as needed (limited only by memory) — `LinkedList`,\n`ArrayDeque`, `PriorityQueue`, `ConcurrentLinkedQueue`,\n`LinkedBlockingQueue` (default). A **bounded** queue has a **fixed maximum\ncapacity** set at construction — `ArrayBlockingQueue`, or `LinkedBlockingQueue`\ngiven a capacity.\n\n```java\nQueue\u003CInteger> unbounded = new ArrayDeque\u003C>();          \u002F\u002F grows freely\nBlockingQueue\u003CInteger> bounded = new ArrayBlockingQueue\u003C>(2); \u002F\u002F cap 2\nbounded.offer(1); bounded.offer(2);\nbounded.offer(3);   \u002F\u002F false — full, rejected (offer form)\n```\n\nBounds matter for **back-pressure**: a bounded queue between a producer and\nconsumer prevents a fast producer from exhausting memory. On a full bounded\nqueue, `add` throws, `offer` returns `false`, and `put` (blocking) waits.\n",{"id":2903,"difficulty":105,"q":2904,"a":2905},"blockingqueue","What is a BlockingQueue and what does it add?","`BlockingQueue\u003CE>` (in `java.util.concurrent`) is a thread-safe queue that adds\noperations which **block** instead of failing: `put(e)` waits while the queue is\nfull, and `take()` waits while it's empty. This is the foundation of the\n**producer-consumer** pattern.\n\n```java\nBlockingQueue\u003CTask> q = new LinkedBlockingQueue\u003C>();\n\n\u002F\u002F producer thread\nq.put(task);     \u002F\u002F blocks if full\n\n\u002F\u002F consumer thread\nTask t = q.take(); \u002F\u002F blocks until an element is available\n```\n\nIt also offers timed `offer(e, timeout, unit)` \u002F `poll(timeout, unit)`. Because\nblocking handles the waiting and the queue handles the locking, you rarely need\nmanual `wait`\u002F`notify` for hand-off between threads.\n",{"id":2907,"difficulty":105,"q":2908,"a":2909},"blockingqueue-impls","What are the main BlockingQueue implementations?","The commonly used ones:\n\n| Implementation | Notes |\n| -------------- | ----- |\n| `ArrayBlockingQueue` | **bounded**, array-backed, single lock, optional fairness |\n| `LinkedBlockingQueue` | optionally bounded, linked nodes, **separate** put\u002Ftake locks (higher throughput) |\n| `PriorityBlockingQueue` | unbounded, priority-ordered, `take` blocks when empty |\n| `SynchronousQueue` | **zero capacity** — each `put` waits for a matching `take` |\n| `DelayQueue` | elements become available only after a delay expires |\n\n```java\nBlockingQueue\u003CRunnable> work = new LinkedBlockingQueue\u003C>();\n\u002F\u002F exactly what a ThreadPoolExecutor uses to hold queued tasks\n```\n\n`ArrayBlockingQueue` and `LinkedBlockingQueue` are the workhorses for bounded\nback-pressure; `SynchronousQueue` is a direct hand-off used by cached thread\npools.\n",{"id":356,"difficulty":126,"q":2911,"a":2912},"How does a BlockingQueue implement the producer-consumer pattern?","Producers `put` work into a shared `BlockingQueue`; consumers `take` from it.\nThe queue handles **all synchronization and waiting**, so neither side touches\nlocks directly — producers block when it's full, consumers block when it's\nempty, decoupling their speeds.\n\n```java\nBlockingQueue\u003CInteger> q = new ArrayBlockingQueue\u003C>(10);\n\nRunnable producer = () -> { while (true) q.put(produce()); };\nRunnable consumer = () -> { while (true) consume(q.take()); };\n```\n\nA bounded queue gives **back-pressure**: if consumers fall behind, the queue\nfills and producers naturally slow down rather than exhausting memory. A common\nshutdown trick is a \"poison pill\" — a sentinel element that tells a consumer to\nstop.\n",{"id":2914,"difficulty":105,"q":2915,"a":2916},"concurrentlinkedqueue","What is ConcurrentLinkedQueue and when would you use it?","`ConcurrentLinkedQueue` is an **unbounded, thread-safe, non-blocking** FIFO\nqueue. It uses **lock-free** CAS (compare-and-swap) algorithms instead of locks,\nso it scales well under high contention — but it **never blocks**: `poll`\nreturns `null` immediately when empty rather than waiting.\n\n```java\nQueue\u003CEvent> q = new ConcurrentLinkedQueue\u003C>();\nq.offer(event);          \u002F\u002F always succeeds (unbounded)\nEvent e = q.poll();      \u002F\u002F null if empty — no waiting\n```\n\nUse it when many threads enqueue\u002Fdequeue and you **don't** need blocking\nhand-off or capacity bounds. If consumers must *wait* for work, use a\n`BlockingQueue` instead. Note `size()` is O(n) and only approximate under\nconcurrency.\n",{"id":2918,"difficulty":126,"q":2919,"a":2920},"blocking-vs-concurrent","When do you choose a BlockingQueue over a ConcurrentLinkedQueue?","Both are thread-safe FIFO queues; the deciding factor is whether consumers need\nto **wait** for elements.\n\n| | `BlockingQueue` (e.g. `LinkedBlockingQueue`) | `ConcurrentLinkedQueue` |\n| --- | --- | --- |\n| Blocks when empty\u002Ffull | yes (`take`\u002F`put`) | no (`poll` returns `null`) |\n| Capacity bound | available (back-pressure) | always unbounded |\n| Mechanism | locks + condition waits | lock-free CAS |\n| Use case | producer-consumer hand-off | high-throughput non-blocking buffer |\n\n```java\n\u002F\u002F consumer must wait for work -> BlockingQueue\nTask t = blockingQueue.take();\n\n\u002F\u002F poll-and-move-on, never wait -> ConcurrentLinkedQueue\nTask t2 = concurrentQueue.poll();\n```\n\nChoose `BlockingQueue` for classic producer-consumer with back-pressure, and\n`ConcurrentLinkedQueue` when threads should drain available work without ever\nblocking.\n",{"id":2922,"difficulty":105,"q":2923,"a":2924},"why-no-nulls","Why do most Queue implementations forbid null elements?","Because `null` is **overloaded as the \"queue is empty\" signal**: `poll()` and\n`peek()` return `null` when there's nothing to return. Allowing a real `null`\nelement would make that signal ambiguous — you couldn't distinguish \"empty\" from\n\"the head happens to be null.\"\n\n```java\nQueue\u003CString> q = new ArrayDeque\u003C>();\nq.offer(null);   \u002F\u002F NullPointerException\n\u002F\u002F if null were allowed, q.poll() == null would be ambiguous\n```\n\n`ArrayDeque`, `PriorityQueue`, `ConcurrentLinkedQueue`, and the blocking queues\nall reject `null`. The lone exception is `LinkedList` (a pre-`Queue` class),\nwhich is one more reason not to use it as a queue.\n",{"id":2926,"difficulty":105,"q":2927,"a":2928},"deque-traversal-direction","How can you iterate a Deque in both directions?","A normal iterator (or for-each) goes **head to tail**. `Deque` adds\n**`descendingIterator()`**, which walks **tail to head** — handy when a deque is\nused as a stack and you want top-to-bottom order, or to reverse without copying.\n\n```java\nDeque\u003CInteger> d = new ArrayDeque\u003C>(List.of(1, 2, 3));\n\nfor (int x : d) System.out.print(x);          \u002F\u002F 123 (head -> tail)\n\nvar it = d.descendingIterator();\nwhile (it.hasNext()) System.out.print(it.next()); \u002F\u002F 321 (tail -> head)\n```\n\nThere's no random access on a `Deque` (no `get(i)`), so these two iterators are\nhow you traverse it. Structurally modifying the deque during iteration throws\n`ConcurrentModificationException`.\n",{"id":2930,"difficulty":113,"q":2931,"a":2932},"remove-vs-poll-empty","What is returned when you poll or peek an empty queue versus remove or element?","It depends on which method family you call. The **returning** family yields\n`null`; the **throwing** family raises `NoSuchElementException`.\n\n```java\nQueue\u003CInteger> q = new ArrayDeque\u003C>();   \u002F\u002F empty\n\nq.poll();      \u002F\u002F null   (returning form)\nq.peek();      \u002F\u002F null   (returning form)\nq.remove();    \u002F\u002F NoSuchElementException (throwing form)\nq.element();   \u002F\u002F NoSuchElementException (throwing form)\n```\n\nSo check with `isEmpty()` or use `poll`\u002F`peek` when emptiness is expected, and\nreserve `remove`\u002F`element` for cases where an empty queue means a programming\nerror you want surfaced loudly.\n",{"description":103},"Java Queue and Deque interview questions — the Queue and Deque interfaces, ArrayDeque vs LinkedList, PriorityQueue, the two method families (throwing vs returning), and blocking queues.","java\u002Fcollections\u002Fqueue-deque","Queue & Deque","P1bd1YfI2HhW1lc6rU5Pvf_lVObUEOkWY4Emz71jbxA",{"id":2939,"title":2940,"body":2941,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":2945,"navigation":108,"order":47,"path":2946,"questions":2947,"questionsCount":1764,"related":250,"seo":3025,"seoDescription":3026,"stem":3027,"subtopic":2940,"topic":72,"topicSlug":74,"updated":809,"__hash__":3028},"qa\u002Fjava\u002Fconcurrency\u002Fconcurrent-collections.md","Concurrent Collections",{"type":100,"value":2942,"toc":2943},[],{"title":103,"searchDepth":29,"depth":29,"links":2944},[],{},"\u002Fjava\u002Fconcurrency\u002Fconcurrent-collections",[2948,2952,2956,2960,2964,2968,2972,2976,2980,2983,2987,2991,2995,2999,3002,3006,3009,3013,3017,3021],{"id":2949,"difficulty":105,"q":2950,"a":2951},"why-concurrent-collections","Why use java.util.concurrent collections instead of Collections.synchronizedX?","`Collections.synchronizedMap`\u002F`synchronizedList` wrap a plain collection so that\n**every method holds one lock on the whole object**. That's correct but it\n**serializes all access** — readers block writers and each other — so it doesn't\nscale under contention. The `java.util.concurrent` collections use **finer-grained\nlocking and lock-free techniques** (CAS, lock striping, copy-on-write) so many\nthreads can proceed at once.\n\n```java\nMap\u003CString,Integer> a = Collections.synchronizedMap(new HashMap\u003C>()); \u002F\u002F one lock\nMap\u003CString,Integer> b = new ConcurrentHashMap\u003C>();                    \u002F\u002F scalable\n```\n\nThe other win: concurrent collections give **weakly consistent iterators** that\nnever throw `ConcurrentModificationException`, whereas iterating a synchronized\nwrapper still requires you to **manually synchronize on it** for the whole loop.\n**Rule of thumb:** reach for `ConcurrentHashMap`\u002F`CopyOnWriteArrayList` first; the\nsynchronized wrappers are legacy.\n",{"id":2953,"difficulty":105,"q":2954,"a":2955},"why-not-raw-hashmap","What goes wrong if multiple threads use a plain HashMap?","A `HashMap` is **not thread-safe**, and concurrent writes can corrupt it. Beyond\nlost updates, a resize happening while another thread reads can leave the internal\nbucket structure in an inconsistent state — in older JDKs this could even spin a\nthread into an **infinite loop** (a hung CPU core). Behavior is simply\n**undefined**, which is worse than a clean exception.\n\n```java\nMap\u003CInteger,Integer> m = new HashMap\u003C>();\n\u002F\u002F two threads both doing m.put(...) concurrently:\n\u002F\u002F -> lost entries, corrupted buckets, or a CPU-pegging infinite loop\n```\n\nYou can't \"mostly get away with it\" — the failure is intermittent and\ncatastrophic. **Rule of thumb:** if a map is shared across threads, use\n`ConcurrentHashMap`; a raw `HashMap` is only safe when confined to one thread or\npublished immutably.\n",{"id":2957,"difficulty":126,"q":2958,"a":2959},"concurrenthashmap-internals","How does ConcurrentHashMap achieve thread-safety?","Since **Java 8** it locks at the **individual bucket (bin)** level, not the whole\nmap. An empty bucket is populated with a single **CAS** (compare-and-swap, no\nlock); a non-empty bucket is updated under a `synchronized` block on that bin's\nfirst node. Because locking is per-bucket, threads touching **different buckets\nnever contend**.\n\n```java\n\u002F\u002F conceptually, per bucket:\nif (bucket == null) casBucket(node);   \u002F\u002F lock-free fast path\nelse synchronized (firstNode) { ... }  \u002F\u002F only this bin is locked\n```\n\nReads are **lock-free** — fields are `volatile`, so a `get` sees a consistent value\nwithout acquiring any lock. (Pre-Java 8 it used **segment** locking, typically 16\nstripes, which is the older \"lock striping\" answer.) **Rule of thumb:** writes\nlock one bin; reads lock nothing — that's why it scales.\n",{"id":2961,"difficulty":105,"q":2962,"a":2963},"chm-no-null","Why does ConcurrentHashMap forbid null keys and values?","`ConcurrentHashMap` throws `NullPointerException` on a `null` key or value, unlike\n`HashMap` which allows them. The reason is **ambiguity in a concurrent setting**:\nwith `get(key)` returning `null`, you can't tell whether the key is **absent** or\n**mapped to null** — and you can't fix it with `containsKey` because another thread\nmay change the mapping between the two calls (a race).\n\n```java\nMap\u003CString,String> m = new ConcurrentHashMap\u003C>();\nm.put(\"k\", null);   \u002F\u002F NullPointerException\nm.get(\"missing\");   \u002F\u002F null is now an unambiguous \"absent\"\n```\n\nBy banning `null`, a `null` return **always** means \"not present,\" which keeps the\nlock-free read path sound. **Rule of thumb:** never store `null` in a concurrent\nmap — use a sentinel value or `Optional` if absence must be distinguished.\n",{"id":2965,"difficulty":126,"q":2966,"a":2967},"chm-atomic-ops","What atomic operations does ConcurrentHashMap provide?","It exposes **atomic compound operations** so you don't have to lock externally for\ncheck-then-act patterns:\n\n| Method | Atomic behavior |\n| ------ | --------------- |\n| `putIfAbsent(k,v)` | put only if key absent |\n| `computeIfAbsent(k,f)` | compute & store if missing (one-time init) |\n| `computeIfPresent(k,f)` | update only if present |\n| `compute(k,f)` | recompute from current value |\n| `merge(k,v,f)` | combine new value with existing |\n\n```java\nConcurrentHashMap\u003CString,Integer> counts = new ConcurrentHashMap\u003C>();\ncounts.merge(\"hits\", 1, Integer::sum);   \u002F\u002F atomic increment-or-init\nList\u003CObject> cache = counts.computeIfAbsent(\"x\", k -> new ArrayList\u003C>()); \u002F\u002F safe lazy init\n```\n\nEach runs atomically with the bin locked, so two threads can't interleave the\nread and the write. **Rule of thumb:** prefer `merge`\u002F`compute*` over\n`get`-then-`put`, which is **not** atomic even on a concurrent map.\n",{"id":2969,"difficulty":105,"q":2970,"a":2971},"chm-size-approximate","Why is ConcurrentHashMap.size() considered approximate?","Because the map is **never globally locked**, `size()` cannot freeze every bucket\nto count exactly. Internally it sums per-bin counters (a striped `LongAdder`-style\ntally), and entries can be added or removed **while** that sum is computed, so the\nreturned value is a **snapshot that may already be stale**.\n\n```java\nint n = map.size();        \u002F\u002F a hint, not a guarantee\n\u002F\u002F mappingCount() returns a long — preferred for very large maps\nlong exact = map.mappingCount();\n```\n\nIt's fine for metrics or sizing heuristics, but never use it for exact control\nflow (`if (size() == capacity)`) under concurrent writes. **Rule of thumb:** treat\n`size()` on any concurrent collection as an **estimate**, and prefer\n`mappingCount()` for big maps.\n",{"id":2973,"difficulty":126,"q":2974,"a":2975},"fail-fast-vs-weakly-consistent","What is the difference between fail-fast and weakly consistent iterators?","A **fail-fast** iterator (`HashMap`, `ArrayList`) tracks a `modCount`; if the\ncollection is structurally modified during iteration it throws\n`ConcurrentModificationException` to surface the bug immediately. A **weakly\nconsistent** (or **fail-safe**) iterator from a concurrent collection **never\nthrows** it — it traverses a live or snapshot view that tolerates concurrent\nchanges.\n\n```java\nMap\u003CInteger,Integer> chm = new ConcurrentHashMap\u003C>(Map.of(1,1,2,2));\nfor (var e : chm.entrySet()) chm.put(99, 99);  \u002F\u002F no exception\n\nMap\u003CInteger,Integer> hm = new HashMap\u003C>(Map.of(1,1));\nfor (var e : hm.entrySet()) hm.put(99, 99);    \u002F\u002F ConcurrentModificationException\n```\n\nThe trade-off: a weakly consistent iterator **may or may not reflect** changes\nmade after it started — it gives no freshness guarantee. **Rule of thumb:**\nfail-fast = bug detector for single-threaded code; weakly consistent = safe\ntraversal under concurrency, but possibly slightly stale.\n",{"id":2977,"difficulty":126,"q":2978,"a":2979},"copyonwritearraylist","How does CopyOnWriteArrayList work and when should you use it?","Every **mutation** (`add`, `set`, `remove`) creates a **fresh copy** of the entire\nbacking array under a lock and swaps it in. Reads and iterators work against the\n**immutable snapshot** that existed when they started, so reads are completely\n**lock-free** and iterators never throw `ConcurrentModificationException`.\n\n```java\nList\u003CListener> listeners = new CopyOnWriteArrayList\u003C>();\nlisteners.add(l);                  \u002F\u002F copies whole array\nfor (Listener x : listeners)       \u002F\u002F iterates a frozen snapshot\n    x.onEvent();                   \u002F\u002F safe even if another thread adds\n```\n\nThe cost is **O(n) per write** plus a full array allocation, so it only pays off\nwhen reads vastly outnumber writes — the classic case is a rarely-changing\n**listener\u002Fobserver list**. **Rule of thumb:** use it for read-mostly, small,\nseldom-mutated lists; never for write-heavy or large collections.\n",{"id":2085,"difficulty":105,"q":2981,"a":2982},"What is CopyOnWriteArraySet?","A `Set` backed by a `CopyOnWriteArrayList`, with the **same snapshot semantics**:\nlock-free reads, copy-on-write mutations, and iterators that never throw. Because\nit stores elements in an array and checks duplicates with `equals` on add, add and\n`contains` are **O(n)** — there's no hashing.\n\n```java\nSet\u003CString> tags = new CopyOnWriteArraySet\u003C>();\ntags.add(\"a\");   \u002F\u002F scans for duplicate, then copies array\n```\n\nIt suits **small, read-mostly** sets (e.g. a handful of subscribers). For larger\nor write-heavy sets, prefer `ConcurrentHashMap.newKeySet()` (a concurrent hash\nset) which gives O(1) operations. **Rule of thumb:** `CopyOnWriteArraySet` for\ntiny read-dominated sets only.\n",{"id":2984,"difficulty":105,"q":2985,"a":2986},"blockingqueue-overview","What is a BlockingQueue and what makes it \"blocking\"?","A `BlockingQueue` is a thread-safe queue whose **`put`** waits when the queue is\nfull and whose **`take`** waits when it's empty — the blocking handles the\ncoordination so threads don't busy-wait. It's the backbone of the\n**producer-consumer** pattern and of `ThreadPoolExecutor`'s work queue.\n\n```java\nBlockingQueue\u003CTask> q = new LinkedBlockingQueue\u003C>(100);\n\u002F\u002F producer\nq.put(task);              \u002F\u002F blocks if full\n\u002F\u002F consumer\nTask t = q.take();        \u002F\u002F blocks until an item is available\n```\n\nIt offers method families with different failure modes: throw (`add`\u002F`remove`),\nreturn special value (`offer`\u002F`poll`), block (`put`\u002F`take`), and time out\n(`offer(e,t,u)`\u002F`poll(t,u)`). **Rule of thumb:** use `put`\u002F`take` for\nproducer-consumer hand-off; the blocking does the waiting and signaling for you.\n",{"id":2988,"difficulty":126,"q":2989,"a":2990},"blockingqueue-implementations","What are the main BlockingQueue implementations and their differences?","| Implementation | Characteristics |\n| -------------- | --------------- |\n| `ArrayBlockingQueue` | bounded, array-backed, single lock, FIFO |\n| `LinkedBlockingQueue` | optionally bounded, linked nodes, **separate put\u002Ftake locks** (higher throughput) |\n| `PriorityBlockingQueue` | unbounded, ordered by comparator (not FIFO) |\n| `DelayQueue` | elements become available only after their delay expires |\n| `SynchronousQueue` | **zero capacity** — each put hands directly to a take |\n\n```java\nBlockingQueue\u003CJob> q = new ArrayBlockingQueue\u003C>(50);  \u002F\u002F fixed back-pressure\nBlockingQueue\u003CJob> p = new PriorityBlockingQueue\u003C>(); \u002F\u002F highest-priority first\n```\n\nBounded queues provide **back-pressure** (producers block when full), which is\nusually what you want in a pipeline. **Rule of thumb:** `ArrayBlockingQueue` for a\nsimple bounded buffer, `LinkedBlockingQueue` for higher throughput,\n`PriorityBlockingQueue`\u002F`DelayQueue` when ordering or timing matters.\n",{"id":2992,"difficulty":126,"q":2993,"a":2994},"synchronousqueue","What is a SynchronousQueue and where is it used?","A `SynchronousQueue` has **no internal capacity** — it holds zero elements. A\n`put` **blocks until another thread does a `take`** (and vice versa), so it's a\ndirect **hand-off** rather than a buffer. Each insert must rendezvous with a\nremoval.\n\n```java\nSynchronousQueue\u003CTask> q = new SynchronousQueue\u003C>();\n\u002F\u002F producer thread: q.put(task) parks until a consumer is ready\n\u002F\u002F consumer thread: q.take() picks it up directly\n```\n\nIt's the work queue used by **`Executors.newCachedThreadPool()`**: a task is\nhanded straight to an idle thread, or a new thread is spawned if none is free.\n**Rule of thumb:** use it for direct hand-off where you want a task picked up\nimmediately or not queued at all.\n",{"id":2996,"difficulty":105,"q":2997,"a":2998},"delayqueue","What is a DelayQueue?","A `DelayQueue` holds elements implementing `Delayed`; an element can only be\n**taken once its delay has elapsed**. `take` blocks until the head element's delay\nexpires, making it ideal for **scheduled** or **expiring** work (caches, retries,\ntimeouts).\n\n```java\nclass Expiring implements Delayed {\n  long readyAt;\n  public long getDelay(TimeUnit u){ return u.convert(readyAt - now(), MILLISECONDS); }\n  public int compareTo(Delayed o){ \u002F* order by readyAt *\u002F }\n}\nDelayQueue\u003CExpiring> q = new DelayQueue\u003C>();\n```\n\nIt's internally a `PriorityQueue` ordered by remaining delay, so the soonest-ready\nitem is always at the head. **Rule of thumb:** reach for `DelayQueue` when items\nmust \"become available later,\" instead of polling with `sleep`.\n",{"id":2914,"difficulty":126,"q":3000,"a":3001},"How is ConcurrentLinkedQueue different from a BlockingQueue?","`ConcurrentLinkedQueue` (and `ConcurrentLinkedDeque`) is an **unbounded,\nnon-blocking, lock-free** FIFO queue built on **CAS** (the Michael-Scott\nalgorithm). Its `offer`\u002F`poll` never block — `poll` simply returns `null` when the\nqueue is empty rather than waiting.\n\n```java\nQueue\u003CEvent> q = new ConcurrentLinkedQueue\u003C>();\nq.offer(e);              \u002F\u002F never blocks, never full\nEvent e = q.poll();      \u002F\u002F returns null if empty (no waiting)\n```\n\nUse it for high-throughput hand-off where consumers can **do other work** when the\nqueue is empty (poll-and-continue), not where you want a thread to **wait** for an\nitem. **Rule of thumb:** lock-free `ConcurrentLinkedQueue` for non-blocking\npipelines; a `BlockingQueue` when consumers should block on `take`.\n",{"id":3003,"difficulty":126,"q":3004,"a":3005},"concurrentskiplistmap","What is ConcurrentSkipListMap and when would you use it?","It's a **sorted**, thread-safe map — the concurrent equivalent of `TreeMap`,\nimplementing `ConcurrentNavigableMap`. Instead of a red-black tree it uses a\n**lock-free skip list**, so it keeps keys ordered while supporting concurrent\naccess without global locking. Operations are **O(log n)**.\n\n```java\nConcurrentNavigableMap\u003CLong,Order> book = new ConcurrentSkipListMap\u003C>();\nbook.put(price, order);\nvar cheapest = book.firstEntry();        \u002F\u002F ordered access\nvar window   = book.headMap(limit);      \u002F\u002F range views, thread-safe\n```\n\nYou get the navigation methods (`firstKey`, `ceilingEntry`, `subMap`) that\n`ConcurrentHashMap` lacks. `ConcurrentSkipListSet` is the sorted-set counterpart.\n**Rule of thumb:** use it when you need **both** thread-safety and **sorted\u002Frange**\nqueries; if you only need a hash map, `ConcurrentHashMap` is faster.\n",{"id":328,"difficulty":105,"q":3007,"a":3008},"What are the atomic classes in java.util.concurrent.atomic?","Classes like `AtomicInteger`, `AtomicLong`, `AtomicBoolean`, and\n`AtomicReference\u003CT>` provide **lock-free, thread-safe** single-variable updates\nbacked by hardware **CAS** instructions. They turn a read-modify-write into one\natomic step without `synchronized`.\n\n```java\nAtomicInteger counter = new AtomicInteger();\ncounter.incrementAndGet();          \u002F\u002F atomic ++\ncounter.addAndGet(5);               \u002F\u002F atomic += 5\n\nAtomicReference\u003CNode> head = new AtomicReference\u003C>();\nhead.compareAndSet(oldHead, newHead); \u002F\u002F atomic pointer swap\n```\n\nThey're far cheaper than a lock under moderate contention because there's no\nblocking or context switch — just a retry loop on CAS. **Rule of thumb:** for a\nsingle shared counter or flag, an atomic class beats a `synchronized` block.\n",{"id":3010,"difficulty":126,"q":3011,"a":3012},"compare-and-set","How does compareAndSet (CAS) work?","`compareAndSet(expected, new)` atomically sets the value to `new` **only if** it\ncurrently equals `expected`, returning `true`\u002F`false`. It maps to a single CPU\ninstruction, so no lock is held. Code that wants to update based on the current\nvalue loops: read, compute, CAS, **retry if it failed** because another thread won\nthe race.\n\n```java\nAtomicInteger v = new AtomicInteger();\nint cur, next;\ndo {\n  cur  = v.get();\n  next = cur * 2;\n} while (!v.compareAndSet(cur, next));   \u002F\u002F retry on contention\n```\n\nThis is **optimistic concurrency** — assume no conflict, verify at commit. The\n`updateAndGet`\u002F`accumulateAndGet` helpers wrap that loop for you. **Rule of\nthumb:** CAS shines under low-to-moderate contention; under heavy contention the\nretry loop wastes CPU and a different structure may win.\n",{"id":3014,"difficulty":126,"q":3015,"a":3016},"longadder","When should you use LongAdder instead of AtomicLong?","Under **high contention**, an `AtomicLong` becomes a bottleneck: every thread CASes\nthe **same** cell, so most attempts fail and retry. `LongAdder` spreads writes\nacross **multiple internal cells** (one per contending thread, roughly), so threads\nrarely collide; `sum()` adds the cells together when you need the total.\n\n```java\nLongAdder hits = new LongAdder();\nhits.increment();          \u002F\u002F updates a per-thread cell, low contention\nlong total = hits.sum();   \u002F\u002F combines all cells (a snapshot)\n```\n\nThe trade-off: it uses more memory and `sum()` is **not** a perfectly atomic\ninstant value (it's accurate when quiescent). Use it for **write-heavy counters**\n(metrics, statistics) where you read the total infrequently. **Rule of thumb:**\nmany threads incrementing -> `LongAdder`; you need the live value on every update ->\n`AtomicLong`.\n",{"id":3018,"difficulty":126,"q":3019,"a":3020},"compound-action-atomicity","If each method is thread-safe, why can a sequence of calls still be a race?","Per-method thread-safety guarantees each **individual** call is atomic — it does\n**not** make a **sequence** of calls atomic. A classic **check-then-act** like\n\"if absent, put\" can interleave: two threads both see \"absent\" and both put.\n\n```java\n\u002F\u002F BROKEN even on a ConcurrentHashMap:\nif (!map.containsKey(k)) map.put(k, v);   \u002F\u002F two threads can both pass the check\n\n\u002F\u002F CORRECT — single atomic operation:\nmap.putIfAbsent(k, v);\n```\n\nThe fix is to use the collection's **built-in atomic compound method**\n(`putIfAbsent`, `compute`, `merge`) or, if none fits, wrap the whole sequence in\nexternal synchronization. **Rule of thumb:** thread-safe per call ≠ thread-safe per\ntransaction — make compound actions atomic explicitly.\n",{"id":3022,"difficulty":105,"q":3023,"a":3024},"newkeyset","How do you get a concurrent Set in Java?","There's no `ConcurrentHashSet` class, so you use `ConcurrentHashMap.newKeySet()`,\nwhich returns a `Set` backed by a `ConcurrentHashMap` (values are a shared dummy\nobject). It gives **O(1)**, fully concurrent set operations with the same\nlock-free reads as the map.\n\n```java\nSet\u003CString> seen = ConcurrentHashMap.newKeySet();\nseen.add(\"a\");                 \u002F\u002F concurrent, O(1)\nboolean isNew = seen.add(\"b\"); \u002F\u002F returns false if already present\n```\n\nThis is the right choice for a large, write-heavy concurrent set;\n`CopyOnWriteArraySet` only suits tiny read-mostly cases, and\n`ConcurrentSkipListSet` is for when you need **sorted** order. **Rule of thumb:**\nfor a general-purpose thread-safe `Set`, use `ConcurrentHashMap.newKeySet()`.\n",{"description":103},"Java concurrent collections interview questions — ConcurrentHashMap, CopyOnWriteArrayList, BlockingQueue, the atomic classes, synchronized wrappers vs concurrent collections, and weakly consistent iterators.","java\u002Fconcurrency\u002Fconcurrent-collections","TBVG-gficrxEkHeWSKWmorxyrBLCwC-e3gy4nywN0_8",{"id":3030,"title":3031,"body":3032,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":3036,"navigation":108,"order":47,"path":3037,"questions":3038,"questionsCount":805,"related":250,"seo":3118,"seoDescription":3119,"stem":3120,"subtopic":3121,"topic":20,"topicSlug":21,"updated":809,"__hash__":3122},"qa\u002Fjava\u002Ffundamentals\u002Fkeywords-modifiers.md","Keywords Modifiers",{"type":100,"value":3033,"toc":3034},[],{"title":103,"searchDepth":29,"depth":29,"links":3035},[],{},"\u002Fjava\u002Ffundamentals\u002Fkeywords-modifiers",[3039,3042,3046,3050,3053,3057,3061,3065,3069,3073,3076,3080,3084,3088,3091,3093,3096,3099,3102,3106,3110,3114],{"id":1040,"difficulty":113,"q":3040,"a":3041},"What are the four access modifiers in Java and what do they control?","Access modifiers control **visibility** — who can see a class, field, method,\nor constructor. There are four levels, from most to least restrictive:\n\n| Modifier | Same class | Same package | Subclass (other pkg) | Everywhere |\n| -------- | :--------: | :----------: | :------------------: | :--------: |\n| `private` | yes | no | no | no |\n| *(default)* | yes | yes | no | no |\n| `protected` | yes | yes | yes | no |\n| `public` | yes | yes | yes | yes |\n\n```java\npublic class Account {\n  private double balance;   \u002F\u002F only this class\n  String owner;             \u002F\u002F package-private (no keyword)\n  protected int id;         \u002F\u002F package + subclasses\n  public String getOwner() { return owner; } \u002F\u002F anyone\n}\n```\n\n\"Default\" (also called **package-private**) is what you get with **no keyword**\n— it is not a keyword itself. The guiding principle: declare everything as\n**private** as you can and widen only when there's a real need.\n",{"id":3043,"difficulty":105,"q":3044,"a":3045},"private-vs-protected","What is the difference between private and protected?","**`private`** restricts a member to its **own class** — not even subclasses can\nsee it. **`protected`** widens that to the **same package plus any subclass**,\nincluding subclasses in a different package (the one case package-private\ndoesn't cover).\n\n```java\npackage base;\npublic class Animal {\n  private String dna;       \u002F\u002F hidden from everyone but Animal\n  protected String species; \u002F\u002F visible to subclasses & same package\n}\n\npackage zoo;\nclass Dog extends Animal {\n  void show() {\n    \u002F\u002F System.out.println(dna);     \u002F\u002F won't compile — private\n    System.out.println(species);     \u002F\u002F OK — protected, inherited\n  }\n}\n```\n\nUse `private` for true implementation detail and `protected` only when you\nintend a member to be part of the **inheritance contract**.\n",{"id":3047,"difficulty":113,"q":3048,"a":3049},"static-meaning","What does the static keyword mean?","`static` binds a member to the **class itself** rather than to any instance.\nThere is exactly **one copy** shared by all objects, and you access it through\nthe class name — no `new` required. It applies to fields, methods, nested\nclasses, and initializer blocks.\n\n```java\nclass MathUtil {\n  static final double PI = 3.14159;   \u002F\u002F one shared constant\n  static int square(int n) {          \u002F\u002F call without an instance\n    return n * n;\n  }\n}\nMathUtil.square(5);   \u002F\u002F 25 — no object created\nMathUtil.PI;          \u002F\u002F shared field\n```\n\nA `static` method **can't use `this`** or access instance fields directly,\nbecause there's no particular object in play. Statics load with the class and\nlive for the program's lifetime.\n",{"id":635,"difficulty":105,"q":3051,"a":3052},"What is the difference between a static member and an instance member?","A **static** member belongs to the **class** — one shared copy for the whole\nprogram. An **instance** member belongs to each **object** — every `new` gets\nits own copy.\n\n```java\nclass Counter {\n  static int total;   \u002F\u002F one shared across all Counters\n  int id;             \u002F\u002F one per instance\n  Counter() { id = ++total; }\n}\nnew Counter(); \u002F\u002F id=1, total=1\nnew Counter(); \u002F\u002F id=2, total=2  (total is shared)\n```\n\nStatic methods can only touch static state; instance methods can touch both.\nYou can call a static member before any object exists, whereas instance members\nrequire an object. Mutable static state is shared globally, which makes it a\ncommon source of threading bugs and memory leaks.\n",{"id":3054,"difficulty":105,"q":3055,"a":3056},"static-nested-class","What is the difference between a static nested class and an inner class?","A **`static` nested class** is a class declared `static` inside another; it does\n**not** hold a reference to an enclosing instance and can be created on its own.\nA non-static nested class (an **inner class**) is tied to an outer instance and\ncan access its members.\n\n```java\nclass Outer {\n  int x = 10;\n  static class Nested {        \u002F\u002F no link to an Outer instance\n    int sum(int a) { return a + 5; }\n  }\n  class Inner {                \u002F\u002F bound to an Outer instance\n    int read() { return x; }   \u002F\u002F can use outer's x\n  }\n}\nOuter.Nested n = new Outer.Nested();        \u002F\u002F no Outer needed\nOuter.Inner i = new Outer().new Inner();    \u002F\u002F needs an Outer\n```\n\nPrefer **`static` nested** unless the class genuinely needs the outer instance —\ninner classes silently retain the enclosing object, a frequent memory-leak\ncause.\n",{"id":3058,"difficulty":105,"q":3059,"a":3060},"final-variable","What does final mean for a variable?","A `final` variable can be **assigned only once**. For a primitive that locks the\nvalue; for a reference it locks **which object** the variable points to — the\nobject itself can still be mutated.\n\n```java\nfinal int MAX = 10;     \u002F\u002F MAX = 11; would not compile\nfinal List\u003CString> xs = new ArrayList\u003C>();\nxs.add(\"ok\");           \u002F\u002F mutating the object is allowed\nxs = new ArrayList\u003C>(); \u002F\u002F reassigning the reference is not\n```\n\n`final` applies to local variables, fields, and method parameters, and it's\nrequired (or \"effectively final\" status is) for any local variable captured by\na lambda or anonymous class.\n",{"id":3062,"difficulty":105,"q":3063,"a":3064},"final-method-class","What does final mean for a method or a class?","A **`final` method** can't be **overridden** by a subclass — it fixes the\nbehavior. A **`final` class** can't be **extended** at all (e.g. `String`,\n`Integer`). Both are tools for protecting invariants and enabling optimization.\n\n```java\nclass Base {\n  final void audit() { }    \u002F\u002F subclasses cannot override this\n}\nfinal class Money { }       \u002F\u002F cannot be subclassed\n\u002F\u002F class Cash extends Money {}  \u002F\u002F compile error\n```\n\nMaking a class `final` is a common way to guarantee **immutability** stays\nintact (no subclass can add mutable state or override behavior), and it lets the\ncompiler\u002FJIT inline `final` methods more aggressively.\n",{"id":3066,"difficulty":126,"q":3067,"a":3068},"blank-final","What is a blank final and a final parameter?","A **blank final** is a `final` field declared **without** an initializer; it\nmust then be assigned **exactly once** in every constructor (or an instance\ninitializer) before construction completes. A **final parameter** simply can't\nbe reassigned inside the method body.\n\n```java\nclass Point {\n  final int x;             \u002F\u002F blank final\n  Point(int x) { this.x = x; }   \u002F\u002F must be set here\n\n  int shift(final int by) {\n    \u002F\u002F by = by + 1;        \u002F\u002F illegal — final parameter\n    return x + by;\n  }\n}\n```\n\nBlank finals let you set an immutable field from constructor arguments rather\nthan a fixed literal — the backbone of immutable classes. Static blank finals\nmust be assigned in a `static` block.\n",{"id":3070,"difficulty":126,"q":3071,"a":3072},"final-vs-immutable","Does final make an object immutable?","No. `final` only freezes the **reference**, not the **object's contents**. A\n`final` variable can't be reassigned, but if the object it points to is mutable,\nits state can still change.\n\n```java\nfinal StringBuilder sb = new StringBuilder(\"a\");\nsb.append(\"b\");        \u002F\u002F allowed — object is mutated\n\u002F\u002F sb = new StringBuilder(); \u002F\u002F not allowed — reference is final\n```\n\n**Immutability** is a stronger, design-level property: it requires all fields be\n`final` *and* private, no setters, defensive copies of mutable inputs\u002Foutputs,\nand usually a `final` class. `final` is one ingredient of immutability, not the\nwhole recipe.\n",{"id":3074,"difficulty":113,"q":676,"a":3075},"static-final-constants","The idiom is **`static final`** with an UPPER_SNAKE_CASE name. `static` gives\none shared copy; `final` makes it unassignable. The compiler can **inline**\n`static final` primitive and `String` constants for efficiency.\n\n```java\npublic class Config {\n  public static final int MAX_RETRIES = 3;\n  public static final String APP_NAME = \"Interviews\";\n}\n```\n\nRemember `final` on a reference only freezes the reference — a\n`static final List\u003CString> X = new ArrayList\u003C>()` can still be mutated. Use\n`List.of(...)` or `Collections.unmodifiableList` for a genuinely constant\ncollection.\n",{"id":3077,"difficulty":105,"q":3078,"a":3079},"abstract-class-method","What does the abstract keyword mean for classes and methods?","An **`abstract` method** declares a signature with **no body** — subclasses must\nimplement it. An **`abstract` class** can't be **instantiated**; it exists to be\nextended and may mix abstract methods with concrete ones and state.\n\n```java\nabstract class Shape {\n  abstract double area();        \u002F\u002F no body — subclass must provide it\n  void describe() {              \u002F\u002F concrete method is allowed\n    System.out.println(\"area=\" + area());\n  }\n}\nclass Circle extends Shape {\n  double r;\n  double area() { return Math.PI * r * r; }  \u002F\u002F implementation\n}\n\u002F\u002F new Shape();  \u002F\u002F compile error — abstract class\n```\n\nAny class with even one abstract method **must** be declared `abstract`. Use it\nwhen you want shared code plus mandatory hooks for subclasses to fill in.\n",{"id":3081,"difficulty":126,"q":3082,"a":3083},"abstract-final-conflict","Why can't a method be both abstract and final (or abstract and private\u002Fstatic)?","`abstract` means \"**must be overridden** by a subclass.\" The conflicting\nmodifiers all **prevent overriding**, so the combinations are contradictory and\nrejected at compile time:\n\n| Combination | Why it's illegal |\n| ----------- | ---------------- |\n| `abstract final` | `final` forbids overriding; `abstract` requires it |\n| `abstract static` | `static` methods aren't polymorphic \u002F can't be overridden |\n| `abstract private` | `private` isn't inherited, so it can't be overridden |\n| `abstract synchronized` | nothing to lock — there's no body |\n| `abstract native` | `native` *has* an (external) body; `abstract` has none |\n\n```java\nabstract class C {\n  \u002F\u002F abstract final void a();   \u002F\u002F error\n  \u002F\u002F abstract static void b();  \u002F\u002F error\n  \u002F\u002F abstract private void c(); \u002F\u002F error\n}\n```\n\nThe rule of thumb: `abstract` is only compatible with `public`\u002F`protected`\n(and package-private) — anything that keeps the method open to overriding.\n",{"id":3085,"difficulty":105,"q":3086,"a":3087},"transient","What does the transient keyword do?","`transient` marks an instance field to be **skipped during serialization**. When\na `Serializable` object is written out, transient fields are ignored; on\ndeserialization they come back as their **default** (`0`, `false`, `null`).\n\n```java\nclass Session implements Serializable {\n  String user;                 \u002F\u002F serialized\n  transient String authToken;  \u002F\u002F NOT serialized — restored as null\n  transient int cacheSize;     \u002F\u002F restored as 0\n}\n```\n\nUse it for **sensitive data** (passwords, tokens), values you can **recompute**,\nor non-serializable fields you don't want to persist. `transient` has no effect\non `static` fields (statics aren't part of an instance's serialized state\nanyway).\n",{"id":288,"difficulty":126,"q":3089,"a":3090},"What does the volatile keyword guarantee?","`volatile` tells the JVM a field may be changed by **multiple threads**, so every\nread goes to **main memory** and every write is immediately **visible** to other\nthreads — no caching in a thread-local register. It also establishes a\n**happens-before** ordering, preventing certain instruction reorderings.\n\n```java\nclass Worker {\n  private volatile boolean running = true;  \u002F\u002F visibility guaranteed\n  void stop() { running = false; }          \u002F\u002F seen by the run() thread\n  void run() {\n    while (running) { \u002F* ... *\u002F }           \u002F\u002F won't loop forever\n  }\n}\n```\n\nWhat it does **not** give you is **atomicity** of compound actions:\n`volatile int x; x++;` is still a race (read-modify-write isn't atomic). For\nthat you need `synchronized` or the `Atomic*` classes. Use `volatile` for simple\nflags and the safe-publication of a single value.\n",{"id":284,"difficulty":105,"q":285,"a":3092},"`synchronized` provides **mutual exclusion**: only one thread at a time can hold\na given object's **monitor lock**, so a synchronized block\u002Fmethod runs without\ninterference. It also gives visibility guarantees (a happens-before edge on lock\nrelease\u002Facquire).\n\n```java\nclass Counter {\n  private int count;\n  synchronized void inc() { count++; }   \u002F\u002F locks on 'this'\n\n  private final Object lock = new Object();\n  void update() {\n    synchronized (lock) {                \u002F\u002F locks on a private monitor\n      count += 2;\n    }\n  }\n}\n```\n\nA `synchronized` **method** locks `this` (or the `Class` object for a static\nmethod); a `synchronized` **block** locks the object you name. Prefer a private\nlock object over locking `this` to avoid outside code interfering with your lock.\n",{"id":1012,"difficulty":113,"q":3094,"a":3095},"What is the this keyword used for?","`this` is a reference to the **current object**. Its three common uses:\ndisambiguating a field from a same-named parameter, passing the current object\nto another method, and calling another constructor of the same class\n(`this(...)`).\n\n```java\nclass Point {\n  int x, y;\n  Point(int x, int y) {\n    this.x = x;          \u002F\u002F field vs parameter\n    this.y = y;\n  }\n  Point() {\n    this(0, 0);          \u002F\u002F constructor chaining — must be first statement\n  }\n  Point self() { return this; } \u002F\u002F return the current object\n}\n```\n\n`this` is unavailable in a **`static`** context — there's no current instance.\nThe `this(...)` constructor call, if used, must be the **first** statement.\n",{"id":1871,"difficulty":105,"q":3097,"a":3098},"What is the super keyword used for?","`super` refers to the **parent class**. It does two jobs: calling a superclass\n**constructor** (`super(...)`) and accessing an **overridden** method or hidden\nfield of the parent (`super.method()`).\n\n```java\nclass Animal {\n  String sound() { return \"...\"; }\n  Animal(String name) { \u002F* ... *\u002F }\n}\nclass Dog extends Animal {\n  Dog() {\n    super(\"Rex\");                 \u002F\u002F parent constructor — must be first\n  }\n  @Override String sound() {\n    return super.sound() + \"woof\"; \u002F\u002F call the parent's version\n  }\n}\n```\n\nIf you don't write `super(...)`, the compiler inserts an implicit no-arg\n`super()` — which is why a parent with **only** a parameterized constructor\nforces every subclass to call `super(...)` explicitly.\n",{"id":1883,"difficulty":105,"q":3100,"a":3101},"What does instanceof do, including pattern matching?","`instanceof` tests whether an object is an **instance** of a given type (or a\nsubtype), returning a `boolean`. Since Java 16, **pattern matching** lets you\nbind the result to a typed variable in one step, removing the manual cast.\n\n```java\nObject o = \"hello\";\n\nif (o instanceof String) {            \u002F\u002F classic form\n  String s = (String) o;              \u002F\u002F explicit cast needed\n  System.out.println(s.length());\n}\n\nif (o instanceof String s) {          \u002F\u002F pattern matching (Java 16+)\n  System.out.println(s.length());     \u002F\u002F 's' is already a String\n}\n```\n\nKey facts: `instanceof` on **`null`** is always `false` (so it's a built-in null\nguard), and it's the standard way to make a **downcast** safe before performing\nit.\n",{"id":3103,"difficulty":126,"q":3104,"a":3105},"native-strictfp","What do the native and strictfp keywords do?","Both are rarely written but show up in interviews. **`native`** marks a method\nimplemented in **non-Java code** (typically C\u002FC++) via the JNI — it has no Java\nbody. **`strictfp`** forces floating-point math to follow strict **IEEE-754**\nrules for fully portable, reproducible results across platforms.\n\n```java\nclass Bridge {\n  native void readSensor();   \u002F\u002F body lives in a native library, no { }\n}\n\nstrictfp class Calc {         \u002F\u002F all FP ops here are platform-independent\n  double scale(double x) { return x * 1.1; }\n}\n```\n\n`native` is how the JDK itself reaches OS-level features. `strictfp` mattered\nbecause older JVMs could use wider intermediate precision; as of **Java 17** all\nfloating-point is strict by default, so the keyword is now effectively a no-op.\n",{"id":3107,"difficulty":105,"q":3108,"a":3109},"reserved-unused","Which Java keywords are reserved but never used?","Two words are **reserved keywords** — so you can't use them as identifiers — yet\nthe language assigns them **no function**: **`goto`** and **`const`**.\n\n```java\n\u002F\u002F int goto = 5;   \u002F\u002F compile error — reserved word\n\u002F\u002F int const = 1;  \u002F\u002F compile error — reserved word\n```\n\nThey were reserved deliberately so that programmers coming from C\u002FC++ wouldn't\naccidentally use them and so the language could repurpose them later (it never\ndid). Java uses `final` instead of `const`, and structured control flow plus\n**labeled** `break`\u002F`continue` instead of `goto`.\n",{"id":3111,"difficulty":105,"q":3112,"a":3113},"var-not-keyword","Is var a keyword in Java?","No — `var` (Java 10+) is a **reserved type name**, not a true keyword. That\ndistinction matters: because it isn't a keyword, you can still legally use `var`\nas a **variable, method, or package name** (just not as a class name). It\nprovides **local variable type inference**: the compiler infers the static type\nfrom the initializer.\n\n```java\nvar list = new ArrayList\u003CString>();  \u002F\u002F inferred ArrayList\u003CString>\nvar count = 10;                      \u002F\u002F int — still statically typed\n\nint var = 5;        \u002F\u002F legal! 'var' as an identifier\n\u002F\u002F var var = 5;     \u002F\u002F illegal — can't infer here\n```\n\nRestrictions: local variables **with an initializer** only — never fields, method\nparameters, return types, or `var x;` \u002F `var x = null;`. It's syntactic sugar,\nnot dynamic typing.\n",{"id":3115,"difficulty":126,"q":3116,"a":3117},"combining-modifiers","Can you combine modifiers, and which combinations are illegal?","Many modifiers stack freely (`public static final`), but some combinations are\ncontradictory and rejected by the compiler. The conflicts cluster around\n`abstract` (which **requires** overriding) and the modifiers that **forbid** it.\n\n| Combination | Legal? | Reason |\n| ----------- | :----: | ------ |\n| `public static final` | yes | the classic constant |\n| `private static` | yes | class-scoped helper |\n| `abstract final` | no | one demands overriding, the other forbids it |\n| `abstract static` | no | static methods can't be overridden |\n| `abstract private` | no | private isn't inherited |\n| `final abstract` (class) | no | a final class can't be subclassed\u002Fextended |\n| two access modifiers | no | `public private int x;` is meaningless |\n\n```java\npublic static final int LIMIT = 5;   \u002F\u002F fine\n\u002F\u002F abstract final void f();          \u002F\u002F error — see above\n```\n\nRule of thumb: a member can have **at most one** access modifier, and `abstract`\nis incompatible with anything that closes the door to overriding.\n",{"description":103},"Java keywords and modifiers interview questions — access modifiers, static, final, abstract, the static vs instance distinction, transient and volatile, synchronized, and other reserved keywords.","java\u002Ffundamentals\u002Fkeywords-modifiers","Keywords & Modifiers","gFYBhAKx-MM5RxFGMrin7cBvG0hdlhczHc6Tp43_EFQ",{"id":3124,"title":3125,"body":3126,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":3130,"navigation":108,"order":47,"path":3131,"questions":3132,"questionsCount":3181,"related":250,"seo":3182,"seoDescription":3183,"stem":3184,"subtopic":3125,"topic":90,"topicSlug":92,"updated":809,"__hash__":3185},"qa\u002Fjava\u002Fmodern-java\u002Ftext-blocks.md","Text Blocks",{"type":100,"value":3127,"toc":3128},[],{"title":103,"searchDepth":29,"depth":29,"links":3129},[],{},"\u002Fjava\u002Fmodern-java\u002Ftext-blocks",[3133,3137,3141,3145,3149,3153,3157,3161,3165,3169,3173,3177],{"id":3134,"difficulty":113,"q":3135,"a":3136},"what-are-text-blocks","What are text blocks in Java and what problem do they solve?","**Text blocks** (Java 15, JEP 378) are multi-line string literals enclosed\nin triple double-quotes (`\"\"\"`). They eliminate the need for explicit `\\n`,\n`\\\"`, and string concatenation when embedding multi-line content like JSON,\nSQL, HTML, or XML.\n\n```java\n\u002F\u002F Old way — hard to read, easy to make mistakes:\nString json = \"{\\n\" +\n              \"  \\\"name\\\": \\\"Alice\\\",\\n\" +\n              \"  \\\"age\\\": 30\\n\" +\n              \"}\";\n\n\u002F\u002F Text block — reads like the actual content:\nString json = \"\"\"\n        {\n          \"name\": \"Alice\",\n          \"age\": 30\n        }\n        \"\"\";\n```\n\n**Rule of thumb:** use text blocks for any multi-line string — SQL,\nJSON, HTML, XML, or test fixtures; never concatenate `\\n` manually again.\n",{"id":3138,"difficulty":113,"q":3139,"a":3140},"opening-closing-delimiter","What are the rules for the opening and closing \"\"\" delimiters?","- The **opening** `\"\"\"` must be followed by a newline — content cannot\n  start on the same line as the opening delimiter.\n- The **closing** `\"\"\"` can be on its own line or at the end of the last\n  content line.\n- The position of the closing `\"\"\"` determines the amount of\n  **incidental whitespace** stripped.\n\n```java\n\u002F\u002F Closing \"\"\" on its own line — trailing newline included:\nString s1 = \"\"\"\n        hello\n        world\n        \"\"\";\n\u002F\u002F s1 = \"hello\\nworld\\n\"\n\n\u002F\u002F Closing \"\"\" at end of last line — no trailing newline:\nString s2 = \"\"\"\n        hello\n        world\"\"\";\n\u002F\u002F s2 = \"hello\\nworld\"\n```\n\n**Rule of thumb:** put the closing `\"\"\"` on its own line for content that\nshould end with a newline (files, SQL); inline it to suppress the trailing\nnewline.\n",{"id":3142,"difficulty":105,"q":3143,"a":3144},"incidental-whitespace","What is incidental whitespace and how does the compiler strip it?","**Incidental whitespace** is the leading spaces added to align a text\nblock with the surrounding code indentation. The compiler removes it\nautomatically, keeping only the relative indentation within the block.\n\nThe algorithm finds the **common leading whitespace prefix** across all\nnon-blank content lines and the closing delimiter line, then strips that\nprefix from every line:\n\n```java\nString sql = \"\"\"\n        SELECT *\n        FROM users\n        WHERE active = true\n        \"\"\";\n\u002F\u002F Each content line has 12 spaces; closing \"\"\" has 12 spaces.\n\u002F\u002F Compiler strips 12 spaces → result:\n\u002F\u002F \"SELECT *\\nFROM users\\nWHERE active = true\\n\"\n```\n\nYou can **increase** relative indentation by indenting content lines more\nthan the closing delimiter:\n\n```java\nString indented = \"\"\"\n        outer\n            inner\n        \"\"\";\n\u002F\u002F \"outer\\n    inner\\n\"  — inner has 4 extra spaces relative to outer\n```\n\n**Rule of thumb:** align the closing `\"\"\"` with the minimum indentation\nyou want in the output; the compiler strips everything up to that column.\n",{"id":3146,"difficulty":105,"q":3147,"a":3148},"line-endings","How does Java handle line endings in text blocks?","The Java compiler **normalises** all line endings in text blocks to `\\n`\n(LF) regardless of the OS line ending in the source file. This makes\ntext blocks portable across Windows (CRLF) and Unix (LF) systems without\nany special handling.\n\n```java\nString s = \"\"\"\n        line1\n        line2\n        \"\"\";\n\u002F\u002F Always \"line1\\nline2\\n\" — never \"line1\\r\\nline2\\r\\n\"\n```\n\nIf you explicitly need `\\r\\n` (e.g., for HTTP headers or email), use\nthe `\\r` escape:\n\n```java\nString crlf = \"\"\"\n        Content-Type: text\u002Fhtml\\r\n        Content-Length: 42\\r\n        \\r\n        \"\"\";\n```\n\n**Rule of thumb:** text blocks use `\\n` everywhere — don't worry about\nCRLF portability; handle it explicitly only when the protocol requires it.\n",{"id":3150,"difficulty":105,"q":3151,"a":3152},"text-block-escapes","What new escape sequences were introduced for text blocks?","Java 15 added two new escape sequences specifically for text blocks:\n\n**`\\\u003Cline terminator>`** (line continuation) — suppresses the newline at\nthe end of a line, joining it with the next line. Useful for long logical\nlines you want to wrap visually:\n\n```java\nString sentence = \"\"\"\n        The quick brown fox \\\n        jumps over the lazy dog.\n        \"\"\";\n\u002F\u002F \"The quick brown fox jumps over the lazy dog.\\n\"\n```\n\n**`\\s`** (explicit space) — a single space that prevents trailing-space\nstripping. The compiler strips trailing whitespace from each line; `\\s`\nmarks a space that must be preserved:\n\n```java\nString padded = \"\"\"\n        red  \\s\n        green\\s\n        blue \\s\n        \"\"\";\n\u002F\u002F Each line ends with exactly one trailing space\n```\n\n**Rule of thumb:** use `\\` to join wrapped lines; use `\\s` to preserve\ntrailing spaces that would otherwise be stripped.\n",{"id":3154,"difficulty":113,"q":3155,"a":3156},"formatted-method","How do you interpolate values into a text block?","Text blocks do not support template syntax natively. Use\n`String.formatted()` (or `String.format()`) to substitute values:\n\n```java\nString name = \"Alice\";\nint age = 30;\n\nString json = \"\"\"\n        {\n          \"name\": \"%s\",\n          \"age\": %d\n        }\n        \"\"\".formatted(name, age);\n\u002F\u002F {\"name\":\"Alice\",\"age\":30}\n```\n\n`String.formatted()` (added in Java 15) is the instance-method equivalent\nof `String.format()`, making the chain read naturally after a text block.\n\n**Rule of thumb:** use `.formatted()` for simple substitution; for\ncomplex templates with loops or conditionals, prefer a template engine\n(Mustache, Thymeleaf) rather than string manipulation.\n",{"id":3158,"difficulty":113,"q":3159,"a":3160},"text-block-vs-string","Is a text block a different type from String?","No. A text block is just a **compile-time literal** that produces a\nregular `java.lang.String`. At runtime there is no difference between a\ntext block and a regular `String` literal — they are the same type.\n\n```java\nString a = \"hello\\nworld\\n\";\nString b = \"\"\"\n        hello\n        world\n        \"\"\";\nSystem.out.println(a.equals(b)); \u002F\u002F true — same content, same type\nSystem.out.println(a == b);      \u002F\u002F likely true — interned constants\n```\n\nBecause text blocks are string literals they are **interned** (pooled)\njust like regular literals.\n\n**Rule of thumb:** treat text blocks as a nicer syntax for string\nliterals — same type, same pool, same API.\n",{"id":3162,"difficulty":113,"q":3163,"a":3164},"text-block-sql","Show a realistic example of a text block used for SQL.","Text blocks make multi-line SQL readable and maintainable, preserving\nthe visual structure of the query:\n\n```java\nString query = \"\"\"\n        SELECT u.id, u.name, o.total\n        FROM users u\n        JOIN orders o ON o.user_id = u.id\n        WHERE u.active = true\n          AND o.created_at > :since\n        ORDER BY o.total DESC\n        LIMIT :limit\n        \"\"\";\n\n\u002F\u002F Use with JDBC or JPA:\nQuery q = em.createNativeQuery(query, UserOrderDto.class)\n            .setParameter(\"since\", startDate)\n            .setParameter(\"limit\", 100);\n```\n\nCompare this to the pre-Java-15 alternative of quote-and-concatenate —\nthe text block is directly readable and diffable.\n\n**Rule of thumb:** text blocks are especially valuable for SQL, where\nkeyword alignment (SELECT\u002FFROM\u002FWHERE\u002FORDER BY) aids readability at a glance.\n",{"id":3166,"difficulty":105,"q":3167,"a":3168},"text-block-trailing-whitespace","What happens to trailing whitespace on lines inside a text block?","The compiler **strips trailing whitespace** from every line of a text\nblock. This means spaces or tabs at the end of a content line are silently\nremoved. This is usually desirable (cleaner output), but can surprise you\nif you intend to produce trailing spaces (e.g., in fixed-width formatted\noutput).\n\n```java\nString padded = \"\"\"\n        item     \n        total    \n        \"\"\";\n\u002F\u002F Trailing spaces on each line are GONE:\n\u002F\u002F \"item\\ntotal\\n\"\n```\n\nUse `\\s` to anchor a trailing space that must be preserved:\n\n```java\nString padded = \"\"\"\n        item  \\s\n        total \\s\n        \"\"\";\n\u002F\u002F \"item  \\ntotal \\n\"  — one preserved trailing space per line\n```\n\n**Rule of thumb:** never rely on trailing spaces in text blocks; use\n`\\s` explicitly whenever a trailing space is meaningful.\n",{"id":3170,"difficulty":113,"q":3171,"a":3172},"text-block-html","Show a realistic example of a text block used for HTML.","Text blocks eliminate the visual noise of escaping quotes in HTML\nattributes:\n\n```java\nString html = \"\"\"\n        \u003C!DOCTYPE html>\n        \u003Chtml lang=\"en\">\n        \u003Chead>\n          \u003Cmeta charset=\"UTF-8\">\n          \u003Ctitle>%s\u003C\u002Ftitle>\n        \u003C\u002Fhead>\n        \u003Cbody>\n          \u003Ch1>%s\u003C\u002Fh1>\n        \u003C\u002Fbody>\n        \u003C\u002Fhtml>\n        \"\"\".formatted(title, heading);\n```\n\nPreviously every `\"` inside the HTML needed escaping as `\\\"`, making\nattributes like `lang=\"en\"` look like `lang=\\\"en\\\"` — difficult to read\nand error-prone to edit.\n\n**Rule of thumb:** if your string contains `\"` characters (HTML, JSON,\nSQL string literals), a text block eliminates escape clutter entirely.\n",{"id":3174,"difficulty":105,"q":3175,"a":3176},"text-block-indentation-control","How do you control indentation in the output of a text block programmatically?","Java 15 also added `String.indent(int n)` which adjusts the indentation\nof each line in a string by `n` spaces (positive = add, negative = remove):\n\n```java\nString block = \"\"\"\n        line1\n        line2\n        \"\"\";\n\n\u002F\u002F Add 4 spaces of indentation to every line:\nSystem.out.print(block.indent(4));\n\u002F\u002F     line1\n\u002F\u002F     line2\n\u002F\u002F                ← trailing newline preserved\n\n\u002F\u002F Remove spaces (clamped at 0 per line):\nSystem.out.print(block.indent(-2));\n```\n\n`String.stripIndent()` (also Java 15) performs the same incidental\nwhitespace removal the compiler does, useful for text blocks received\nfrom external sources at runtime.\n\n**Rule of thumb:** use `indent()` for post-processing indentation;\nuse `stripIndent()` to clean up dynamically loaded multi-line strings\nthe same way the compiler cleans text block literals.\n",{"id":3178,"difficulty":113,"q":3179,"a":3180},"text-block-java-version","In which Java version did text blocks become a standard feature?","Text blocks were introduced as a **preview** feature in Java 13 (JEP 355)\nand Java 14 (JEP 368), then finalized as a standard feature in\n**Java 15** (JEP 378). No `--enable-preview` flag is needed in Java 15+.\n\n```java\n\u002F\u002F Java 13\u002F14 — required --enable-preview at compile and runtime\n\u002F\u002F Java 15+   — standard feature, no flag needed\n\nString query = \"\"\"\n        SELECT *\n        FROM orders\n        \"\"\";\n```\n\n**Rule of thumb:** text blocks are available unconditionally in Java 15+;\nif your codebase targets Java 15 or higher you should use them freely\nfor all multi-line string content.\n",12,{"description":103},"Java text blocks interview questions — triple-quote syntax, incidental whitespace stripping, line endings, escape sequences, formatted() method, and comparing text blocks to string concatenation and heredocs.","java\u002Fmodern-java\u002Ftext-blocks","01Xl11eivLS_NDw9BhLS7TxxvE-5YEhzNT9TbxQxKXw",{"id":3187,"title":3188,"body":3189,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":3193,"navigation":108,"order":47,"path":3194,"questions":3195,"questionsCount":980,"related":250,"seo":3254,"seoDescription":3255,"stem":3256,"subtopic":3257,"topic":28,"topicSlug":30,"updated":1068,"__hash__":3258},"qa\u002Fjava\u002Foop\u002Finterfaces-vs-abstract.md","Interfaces Vs Abstract",{"type":100,"value":3190,"toc":3191},[],{"title":103,"searchDepth":29,"depth":29,"links":3192},[],{},"\u002Fjava\u002Foop\u002Finterfaces-vs-abstract",[3196,3200,3204,3208,3212,3216,3220,3224,3226,3230,3234,3238,3242,3246,3250],{"id":3197,"difficulty":113,"q":3198,"a":3199},"abstraction","What is abstraction and how is it achieved in Java?","Abstraction is exposing a **simplified contract** while hiding implementation\ndetail. In Java you achieve it with **interfaces** (pure contract) and\n**abstract classes** (partial implementation). Callers depend on the abstract\ntype, not the concrete class.\n\n```java\ninterface PaymentGateway { void charge(int cents); }\n\nclass StripeGateway implements PaymentGateway {\n  public void charge(int cents) { \u002F* API calls hidden here *\u002F }\n}\n\nPaymentGateway gw = new StripeGateway(); \u002F\u002F code depends only on the contract\n```\n\nThe payoff is decoupling: you can swap `StripeGateway` for `PayPalGateway`\nwithout touching the calling code — the basis of \"program to an interface.\"\n",{"id":3201,"difficulty":105,"q":3202,"a":3203},"abstract-vs-interface","What is the difference between an abstract class and an interface?","- **Abstract class** — can have state (fields), constructors, and a mix of\n  concrete and abstract methods. A class extends **one**. Models an\n  *is-a* with shared implementation.\n- **Interface** — a contract; historically only abstract methods, now also\n  `default`\u002F`static`\u002F`private` methods, but **no instance state** (only\n  `public static final` constants). A class implements **many**.\n\n```java\nabstract class Shape {\n  private String name;            \u002F\u002F state allowed\n  abstract double area();         \u002F\u002F subclasses must implement\n  String describe() { return name + \": \" + area(); }\n}\ninterface Drawable { void draw(); default void hide() { } }\n```\n\nRule of thumb: use an **interface** for a capability multiple unrelated classes\ncan have (`Comparable`, `Runnable`); use an **abstract class** when subclasses\nshare state or implementation and form a tight family.\n",{"id":3205,"difficulty":113,"q":3206,"a":3207},"abstract-class-purpose","What is an abstract class and when can't you instantiate one?","An **abstract class** is declared `abstract` and **cannot be instantiated** with\n`new` — it exists to be extended. It can mix abstract methods (no body, must be\nimplemented) with concrete methods and fields, providing a partial\nimplementation subclasses complete.\n\n```java\nabstract class Animal {\n  abstract String sound();                 \u002F\u002F must override\n  void describe() { System.out.println(\"Says \" + sound()); } \u002F\u002F shared\n}\n\u002F\u002F Animal a = new Animal();  \u002F\u002F ERROR — abstract, can't instantiate\nAnimal a = new Dog();        \u002F\u002F OK via a concrete subclass\n```\n\nA class with **any** abstract method must itself be `abstract` (but an abstract\nclass can have zero abstract methods). **Rule of thumb:** abstract class =\n\"shared base you're not meant to use directly.\"\n",{"id":3209,"difficulty":105,"q":3210,"a":3211},"abstract-constructor","Can an abstract class have a constructor?","Yes. Even though you can't `new` an abstract class directly, its constructor\n**runs when a subclass is instantiated**, via the implicit\u002Fexplicit `super(...)`\ncall — it initializes the abstract class's slice of the object.\n\n```java\nabstract class Shape {\n  final String name;\n  Shape(String name) { this.name = name; }   \u002F\u002F runs during subclass construction\n}\nclass Circle extends Shape {\n  Circle() { super(\"circle\"); }               \u002F\u002F must chain to it\n}\n```\n\nInterfaces, by contrast, **cannot** have constructors (no instance state to\ninitialize). **Rule of thumb:** abstract classes initialize shared state through\ntheir constructor; interfaces can't.\n",{"id":3213,"difficulty":105,"q":3214,"a":3215},"interface-default","What are default methods in interfaces and why were they added?","A **default method** provides a body inside an interface using the `default`\nkeyword. They were added in Java 8 so interfaces could **evolve** — e.g. adding\n`forEach` to `Iterable` — **without breaking** every existing implementer.\n\n```java\ninterface Greeter {\n  String name();\n  default String greet() { return \"Hello, \" + name(); } \u002F\u002F optional to override\n}\n```\n\nIf a class inherits conflicting defaults from two interfaces, it **must\noverride** to resolve the ambiguity (it can call `Iface.super.method()`).\nInterfaces can also have `static` and `private` helper methods now — but still\nno instance state.\n",{"id":3217,"difficulty":105,"q":3218,"a":3219},"interface-static-methods","Can an interface have static and private methods?","Yes (Java 8 added `static`, Java 9 added `private`):\n\n- **`static`** — utility methods called on the interface itself, not inherited\n  by implementers (e.g. `Comparator.comparing(...)`).\n- **`private`** \u002F `private static` — helper methods that share code **between**\n  `default`\u002F`static` methods without exposing it.\n\n```java\ninterface Validator {\n  boolean valid(String s);\n  static Validator notEmpty() { return s -> s != null && !s.isEmpty(); }\n  default boolean validAll(List\u003CString> xs) { return xs.stream().allMatch(this::valid); }\n}\n```\n\n**Rule of thumb:** `static` for factories\u002Futilities tied to the type, `private`\nto DRY up the bodies of default methods — interfaces are now mini-toolkits, not\njust contracts.\n",{"id":3221,"difficulty":113,"q":3222,"a":3223},"interface-constants","Can interfaces have fields? What kind?","Only **constants**. Every field in an interface is implicitly `public static\nfinal`, so it must be assigned at declaration and can never change — there's\n**no instance state**.\n\n```java\ninterface Physics {\n  double SPEED_OF_LIGHT = 299_792_458;   \u002F\u002F implicitly public static final\n}\nPhysics.SPEED_OF_LIGHT;                    \u002F\u002F accessed via the interface\n```\n\nThe old \"constant interface\" pattern (implementing an interface just to inherit\nits constants) is an **anti-pattern** — use an `enum` or a `final` class with a\nprivate constructor instead. **Rule of thumb:** interfaces hold constants and\nbehavior, never mutable state.\n",{"id":1089,"difficulty":105,"q":1090,"a":3225},"A **functional interface** has exactly **one abstract method** (SAM — Single\nAbstract Method), so it can be the target type of a **lambda** or **method\nreference**. The `@FunctionalInterface` annotation makes the compiler enforce\nthe \"one abstract method\" rule.\n\n```java\n@FunctionalInterface\ninterface Transformer { String apply(String s); }\n\nTransformer upper = s -> s.toUpperCase();   \u002F\u002F lambda implements the SAM\nupper.apply(\"hi\");                           \u002F\u002F \"HI\"\n```\n\n`default`\u002F`static` methods don't count against the one-abstract-method limit.\nExamples: `Runnable`, `Comparator`, `Function`, `Predicate`. **Rule of thumb:**\none abstract method = lambda-compatible.\n",{"id":3227,"difficulty":105,"q":3228,"a":3229},"marker-interface","What is a marker interface?","A marker interface has **no methods** — it just *tags* a class so that code (or\nthe JVM) can detect a capability at runtime via `instanceof`. Classic examples:\n`Serializable`, `Cloneable`, `RandomAccess`.\n\n```java\nclass Config implements Serializable { } \u002F\u002F \"this class may be serialized\"\n```\n\nThe JVM checks `if (obj instanceof Serializable)` before serializing. Modern\nJava often prefers **annotations** for metadata, but marker interfaces still\ngive you compile-time type checking and `instanceof` support that annotations\ndon't.\n",{"id":3231,"difficulty":105,"q":3232,"a":3233},"interface-vs-abstract-when","Can a class implement multiple interfaces with the same method?","Yes. If two interfaces declare the **same abstract** method, one implementation\nsatisfies both. But if they provide **conflicting `default`** methods, the class\n**must override** to break the tie, optionally delegating with\n`Interface.super.method()`.\n\n```java\ninterface A { default String hi() { return \"A\"; } }\ninterface B { default String hi() { return \"B\"; } }\n\nclass C implements A, B {\n  @Override public String hi() {\n    return A.super.hi();   \u002F\u002F explicitly choose A's default\n  }\n}\n```\n\nThis is Java's controlled answer to the multiple-inheritance \"diamond problem\":\nmultiple *types* are allowed, but conflicting *behavior* must be resolved\nexplicitly.\n",{"id":3235,"difficulty":105,"q":3236,"a":3237},"interface-multiple-inheritance","How do interfaces give Java a form of multiple inheritance?","A class can `implements` **many** interfaces, inheriting **multiple type\ncontracts** — and, since Java 8, multiple `default` **implementations**. That's\nmultiple inheritance of *type* and *behavior*, without multiple inheritance of\n*state* (which is what causes the classic diamond problem).\n\n```java\ninterface Swimmer { default void move() { System.out.println(\"swim\"); } }\ninterface Flyer   { default void glide() { System.out.println(\"glide\"); } }\nclass Duck implements Swimmer, Flyer { }   \u002F\u002F inherits both behaviors\n```\n\nBecause interfaces hold no instance fields, there's no ambiguous state to merge.\n**Rule of thumb:** interfaces = safe multiple inheritance of capability; classes\n= single inheritance of implementation.\n",{"id":3239,"difficulty":105,"q":3240,"a":3241},"when-interface-vs-abstract","How do you decide between an interface and an abstract class?","Choose by what you need to share:\n\n- **Interface** — a *capability* that unrelated classes can have, multiple\n  inheritance of type, or a lambda target. No shared state.\n- **Abstract class** — a *family* of related classes sharing **fields, a\n  constructor, or substantial implementation**.\n\n```java\ninterface Comparable\u003CT> { int compareTo(T o); }   \u002F\u002F any class can be comparable\nabstract class HttpServlet { \u002F* shared request plumbing + state *\u002F }\n```\n\nThey combine well: declare the API as an interface, offer an\n`AbstractXxx` skeletal class for implementers (like `AbstractList`). **Rule of\nthumb:** default to an interface; reach for an abstract class only when you must\nshare state\u002Fimplementation.\n",{"id":3243,"difficulty":126,"q":3244,"a":3245},"diamond-default","If a class extends a class and implements an interface with the same method, which wins?","The **class** wins — \"**class always beats interface**.\" A concrete method\ninherited from a superclass takes priority over a `default` method from an\ninterface, even if the interface is \"more specific.\"\n\n```java\nclass Base { public String id() { return \"class\"; } }\ninterface Tagged { default String id() { return \"interface\"; } }\n\nclass Item extends Base implements Tagged { }\nnew Item().id();   \u002F\u002F \"class\" — superclass method wins over default\n```\n\nAmong *interfaces*, a more-specific interface's default beats a less-specific\none; ties must be resolved manually. **Rule of thumb:** superclass method >\ninterface default > you must override.\n",{"id":3247,"difficulty":105,"q":3248,"a":3249},"enum-basics","What are enums and what can they do beyond constants?","An `enum` defines a fixed set of named instances. Unlike `int` constants,\nenums are **type-safe**, can have **fields, constructors, and methods**, and\neach constant can even override behavior.\n\n```java\nenum Planet {\n  EARTH(9.81), MARS(3.71);\n  private final double gravity;\n  Planet(double g) { this.gravity = g; }   \u002F\u002F constructor\n  double weight(double mass) { return mass * gravity; }\n}\nPlanet.MARS.weight(70);  \u002F\u002F type-safe, behavior attached\n```\n\nEnums are implicitly `final` singletons (one instance per constant), work in\n`switch`, provide `values()`\u002F`valueOf()`\u002F`ordinal()`, and are the recommended\nway to implement singletons.\n",{"id":3251,"difficulty":105,"q":3252,"a":3253},"enum-implements-interface","Can an enum implement an interface or have abstract methods?","Yes. An enum can `implements` an interface, and it can declare **abstract\nmethods** that **each constant overrides** — giving per-constant behavior (a\nclean replacement for `switch` over the enum).\n\n```java\ninterface Op { int apply(int a, int b); }\nenum Math implements Op {\n  ADD { public int apply(int a, int b) { return a + b; } },\n  MUL { public int apply(int a, int b) { return a * b; } };\n}\nMath.ADD.apply(2, 3);   \u002F\u002F 5 — each constant has its own body\n```\n\nAn enum can't `extends` a class (it implicitly extends `java.lang.Enum`), but\ninterfaces are open to it. **Rule of thumb:** use constant-specific method bodies\nto attach behavior to enum values instead of branching on them.\n",{"description":103},"Java interfaces vs abstract classes interview questions — abstraction, default and static interface methods, functional and marker interfaces, multiple inheritance of behavior, interface constants, enums and when to use each.","java\u002Foop\u002Finterfaces-vs-abstract","Interfaces vs Abstract Classes","BW88jLcXhdNT2Ca6gCGI0mGHs07YWnXKYoWi87ygqtY",{"id":3260,"title":3261,"body":3262,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":3266,"navigation":108,"order":47,"path":3267,"questions":3268,"questionsCount":1764,"related":250,"seo":3346,"seoDescription":3347,"stem":3348,"subtopic":3261,"topic":55,"topicSlug":56,"updated":809,"__hash__":3349},"qa\u002Fjava\u002Fstreams-functional\u002Foptional.md","Optional",{"type":100,"value":3263,"toc":3264},[],{"title":103,"searchDepth":29,"depth":29,"links":3265},[],{},"\u002Fjava\u002Fstreams-functional\u002Foptional",[3269,3273,3277,3281,3285,3289,3293,3297,3300,3303,3306,3310,3314,3318,3322,3326,3330,3334,3338,3342],{"id":3270,"difficulty":113,"q":3271,"a":3272},"what-is-optional","What is Optional and what problem does it solve?","`Optional\u003CT>` (Java 8+) is a **container** that holds either **one value** or\n**nothing** — a typed \"maybe\". Its job is to make the **possible absence of a\nvalue explicit** in the API, instead of returning `null` and hoping the caller\nremembers to check.\n\n```java\n\u002F\u002F before: null is invisible in the signature\nUser find(String id);          \u002F\u002F might return null — caller may forget\n\n\u002F\u002F after: the type screams \"this can be empty\"\nOptional\u003CUser> find(String id); \u002F\u002F caller is forced to handle absence\n```\n\nThe payoff is fewer **`NullPointerException`s**: a returned `Optional` forces\nthe caller to deal with the empty case, and the API documents the \"no result\"\npossibility right in the return type.\n",{"id":3274,"difficulty":113,"q":3275,"a":3276},"optional-of","How do you create an Optional with Optional.of?","`Optional.of(value)` wraps a **non-null** value. If you hand it `null` it throws\n**`NullPointerException`** immediately — by design, so a programming error\nsurfaces at the source rather than far away.\n\n```java\nOptional\u003CString> name = Optional.of(\"Ada\");   \u002F\u002F holds \"Ada\"\nOptional\u003CString> bad  = Optional.of(null);    \u002F\u002F NullPointerException!\n```\n\nUse `of` only when you **know** the value is non-null. If the value might be\n`null`, use `ofNullable` instead — mixing them up is a classic source of an NPE\nwhere you least expect one.\n",{"id":3278,"difficulty":113,"q":3279,"a":3280},"optional-ofnullable-empty","What are Optional.ofNullable and Optional.empty?","`Optional.ofNullable(value)` wraps a value that **might be null** — it returns an\nempty `Optional` for `null` and a present one otherwise. `Optional.empty()`\ngives you an explicitly **empty** `Optional`.\n\n```java\nOptional\u003CString> a = Optional.ofNullable(maybeNull); \u002F\u002F empty if null, else present\nOptional\u003CString> b = Optional.empty();               \u002F\u002F always empty\n\nOptional\u003CUser> find(String id) {\n    return Optional.ofNullable(map.get(id));  \u002F\u002F map.get can return null\n}\n```\n\n`ofNullable` is the safe bridge from legacy null-returning code into the\n`Optional` world. Reach for it whenever the source could be `null`; reserve\n`of` for values you can guarantee.\n",{"id":3282,"difficulty":113,"q":3283,"a":3284},"ispresent-isempty","What do isPresent and isEmpty do?","`isPresent()` returns `true` when the `Optional` holds a value; `isEmpty()`\n(Java 11+) is its inverse. They're simple boolean checks.\n\n```java\nOptional\u003CString> name = find();\nif (name.isPresent()) {\n    System.out.println(name.get());\n}\nif (name.isEmpty()) {           \u002F\u002F Java 11+\n    System.out.println(\"not found\");\n}\n```\n\nBe careful: `isPresent()` followed by `get()` is just `null`-checking dressed up\nin `Optional` clothing — it misses the point. Prefer the functional methods\n(`map`, `ifPresent`, `orElse`) that handle both cases in one expression.\n",{"id":3286,"difficulty":105,"q":3287,"a":3288},"get-avoid","Why should you avoid calling get on an Optional?","`get()` returns the value **only if present**; on an empty `Optional` it throws\n**`NoSuchElementException`**. Calling it without first checking re-creates the\nexact null-pointer hazard `Optional` was meant to remove — you've just swapped\none runtime exception for another.\n\n```java\nOptional\u003CUser> u = find(id);\nUser user = u.get();   \u002F\u002F throws NoSuchElementException if empty!\n```\n\nPrefer methods that **bake in** the absent case: `orElse`, `orElseGet`,\n`orElseThrow`, `map`, or `ifPresent`. If you truly want \"fail loudly when\nmissing\", say so explicitly with `orElseThrow()` rather than `get()`.\n",{"id":3290,"difficulty":113,"q":3291,"a":3292},"ifpresent","What does ifPresent do?","`ifPresent(consumer)` runs the given action **only if** a value is present, and\ndoes nothing when empty — a clean replacement for an `if (isPresent())` block.\n\n```java\nOptional\u003CUser> u = find(id);\nu.ifPresent(user -> System.out.println(user.getName()));\n\n\u002F\u002F equivalent imperative version\nif (u.isPresent()) {\n    System.out.println(u.get().getName());\n}\n```\n\nIt takes a `Consumer`, so it's for **side effects** (printing, saving), not for\nproducing a value. If you also need to handle the empty case, use\n`ifPresentOrElse`.\n",{"id":3294,"difficulty":105,"q":3295,"a":3296},"ifpresentorelse","What is ifPresentOrElse?","`ifPresentOrElse(consumer, runnable)` (Java 9+) runs the **consumer** when a\nvalue is present and the **runnable** when empty — handling both branches in one\ncall.\n\n```java\nfind(id).ifPresentOrElse(\n    user -> System.out.println(\"Found \" + user.getName()),\n    ()   -> System.out.println(\"No user found\")\n);\n```\n\nIt's the functional equivalent of a full `if\u002Felse` on presence. Like\n`ifPresent`, it's side-effect oriented — use `map`\u002F`orElse` when you need to\ncompute and return a value instead.\n",{"id":1954,"difficulty":105,"q":3298,"a":3299},"How does Optional.map work?","`map(function)` **transforms** the contained value if present, returning a new\n`Optional` of the result; if empty, it returns empty and **skips** the function.\nThis lets you chain transformations without ever null-checking.\n\n```java\nOptional\u003CUser> user = find(id);\nOptional\u003CString> upper = user\n    .map(User::getName)        \u002F\u002F Optional\u003CString>\n    .map(String::toUpperCase); \u002F\u002F still Optional\u003CString>, empty stays empty\n```\n\nIf the mapping function returns `null`, `map` treats the result as **empty**\n(it wraps with `ofNullable` internally), so you never get an `Optional` holding\n`null`. Use `map` when your function returns a **plain value**; use `flatMap`\nwhen it returns another `Optional`.\n",{"id":1958,"difficulty":105,"q":3301,"a":3302},"When do you use flatMap instead of map?","Use `flatMap` when the mapping function **itself returns an `Optional`**. `map`\nwould wrap that in another layer, giving you `Optional\u003COptional\u003CT>>`;\n`flatMap` **flattens** it to a single `Optional\u003CT>`.\n\n```java\n\u002F\u002F getAddress() returns Optional\u003CAddress>\nOptional\u003CAddress> addr = find(id).map(User::getAddress);     \u002F\u002F Optional\u003COptional\u003CAddress>>! wrong\nOptional\u003CAddress> ok   = find(id).flatMap(User::getAddress); \u002F\u002F Optional\u003CAddress> — correct\n\n\u002F\u002F chaining nested optionals reads cleanly\nString zip = find(id)\n    .flatMap(User::getAddress)\n    .map(Address::getZip)\n    .orElse(\"unknown\");\n```\n\nRule: mapper returns a **value** -> `map`; mapper returns an **`Optional`** ->\n`flatMap`. It's the same `map`\u002F`flatMap` distinction as in `Stream`.\n",{"id":1950,"difficulty":105,"q":3304,"a":3305},"What does Optional.filter do?","`filter(predicate)` keeps the value **only if** it's present **and** satisfies\nthe predicate; otherwise it returns an empty `Optional`. It lets you add a\ncondition mid-chain without breaking out of the `Optional` flow.\n\n```java\nOptional\u003CUser> active = find(id)\n    .filter(User::isActive);   \u002F\u002F empty if absent OR not active\n\nString name = find(id)\n    .filter(u -> u.getAge() >= 18)\n    .map(User::getName)\n    .orElse(\"ineligible\");\n```\n\nAn empty `Optional` stays empty (the predicate isn't called). It mirrors\n`Stream.filter`, but on a zero-or-one container.\n",{"id":3307,"difficulty":126,"q":3308,"a":3309},"orelse-vs-orelseget","What is the difference between orElse and orElseGet?","Both supply a fallback when the `Optional` is empty, but they differ in\n**when the fallback is evaluated**. `orElse(value)` takes an **already-computed\nvalue** — evaluated **eagerly, always**, even when the `Optional` is present.\n`orElseGet(supplier)` takes a **`Supplier`** invoked **lazily, only** when empty.\n\n```java\n\u002F\u002F expensiveDefault() runs EVERY time, even when a value is present — wasteful\nString a = opt.orElse(expensiveDefault());\n\n\u002F\u002F expensiveDefault() runs ONLY when opt is empty\nString b = opt.orElseGet(() -> expensiveDefault());\n```\n\nThis is the most-tested `Optional` gotcha. If the fallback is cheap (a constant,\na literal), `orElse` is fine. If it's expensive or has **side effects** (a DB\ncall, object creation), use `orElseGet` so it isn't run needlessly.\n",{"id":3311,"difficulty":105,"q":3312,"a":3313},"orelsethrow","What does orElseThrow do?","`orElseThrow(supplier)` returns the value if present, otherwise **throws** the\nexception produced by the supplier — the right way to say \"this must exist, fail\nloudly if not\". Since Java 10 there's also a **no-arg** `orElseThrow()` that\nthrows `NoSuchElementException`.\n\n```java\nUser u = find(id)\n    .orElseThrow(() -> new UserNotFoundException(id)); \u002F\u002F custom exception\n\nUser v = find(id).orElseThrow(); \u002F\u002F Java 10+: throws NoSuchElementException\n```\n\nPrefer `orElseThrow()` over `get()`: it expresses the same intent but reads as a\ndeliberate choice, and the supplier form lets you throw a **meaningful, domain**\nexception with context.\n",{"id":3315,"difficulty":105,"q":3316,"a":3317},"or-method","What does the or method do?","`or(supplier)` (Java 9+) returns the current `Optional` if present, otherwise\nthe `Optional` produced by the supplier. Unlike `orElse`\u002F`orElseGet` (which\nunwrap to a value), `or` keeps you **inside `Optional`** — handy for chaining\nfallback **sources**.\n\n```java\nOptional\u003CConfig> cfg = readFromFile()\n    .or(() -> readFromEnv())       \u002F\u002F try env if file missing\n    .or(() -> Optional.of(DEFAULT)); \u002F\u002F final fallback, still Optional\n```\n\nThe supplier is **lazy** (only called when the current `Optional` is empty), so\nit's the natural \"try the next source\" operator before you finally unwrap with\n`orElse`\u002F`orElseThrow`.\n",{"id":3319,"difficulty":105,"q":3320,"a":3321},"optional-stream","How does Optional.stream bridge to the Stream API?","`stream()` (Java 9+) turns an `Optional` into a `Stream` of **zero or one**\nelement: empty `Optional` -> empty stream, present -> single-element stream. Its\nkiller use is `flatMap`ping a stream of `Optional`s to drop the empties in one\nstep.\n\n```java\nList\u003CUser> users = ids.stream()\n    .map(this::find)            \u002F\u002F Stream\u003COptional\u003CUser>>\n    .flatMap(Optional::stream)  \u002F\u002F Stream\u003CUser> — empties vanish\n    .toList();\n```\n\nBefore Java 9 this needed `.filter(Optional::isPresent).map(Optional::get)`.\n`Optional::stream` is the clean, idiomatic replacement.\n",{"id":3323,"difficulty":105,"q":3324,"a":3325},"optional-primitives","What are OptionalInt, OptionalLong and OptionalDouble?","They are **primitive specializations** of `Optional` that hold an `int`, `long`,\nor `double` **without boxing**. The primitive streams return them from\nreduction methods like `max`, `min`, `average`, and `findFirst`.\n\n```java\nOptionalInt max = IntStream.of(3, 7, 2).max();  \u002F\u002F no Integer boxing\nint result = max.getAsInt();                    \u002F\u002F note: getAsInt, not get\ndouble avg = IntStream.rangeClosed(1, 5).average().orElse(0); \u002F\u002F OptionalDouble\n```\n\nTheir accessors are named for the type (`getAsInt`, `getAsLong`,\n`getAsDouble`), and they have **no `map`\u002F`flatMap`\u002F`filter`** — they're\ndeliberately minimal, meant only to carry a possibly-absent primitive result.\n",{"id":3327,"difficulty":126,"q":3328,"a":3329},"antipattern-fields-params","Why shouldn't you use Optional for fields or method parameters?","`Optional` was designed as a **return type** for \"no result\", not as a general\n\"maybe\" everywhere. Using it for **fields** adds a wrapper object per instance\n(memory overhead) and breaks serialization; using it for **parameters** forces\ncallers to box arguments and creates ambiguous call sites.\n\n```java\n\u002F\u002F anti-pattern: Optional field and parameter\nclass User { private Optional\u003CString> nickname; }       \u002F\u002F avoid\nvoid greet(Optional\u003CString> name) { }                   \u002F\u002F avoid\n\n\u002F\u002F prefer: nullable field, overloads or @Nullable for params\nclass User { private String nickname; }                 \u002F\u002F may be null internally\nvoid greet() { } void greet(String name) { }            \u002F\u002F overloads\n```\n\nThe official guidance (from `Optional`'s own designers) is: use it as a\n**method return type** to signal absence, and don't sprinkle it across fields,\nparameters, or constructor arguments.\n",{"id":3331,"difficulty":105,"q":3332,"a":3333},"antipattern-collections","Why shouldn't you wrap a collection in Optional?","A collection already has a perfect \"nothing\" value: the **empty collection**.\nReturning `Optional\u003CList\u003CT>>` forces the caller to unwrap *and then* still loop,\nwith two ways to mean \"no items\" (empty vs absent) — needless complexity.\n\n```java\n\u002F\u002F anti-pattern\nOptional\u003CList\u003CUser>> getUsers();   \u002F\u002F empty Optional? empty list? ambiguous\n\n\u002F\u002F prefer — return an empty collection\nList\u003CUser> getUsers() {\n    return results != null ? results : Collections.emptyList();\n}\n```\n\n**Rule:** never return `Optional` of a collection, array, or map. Return an\n**empty** one instead, so callers can iterate unconditionally.\n",{"id":3335,"difficulty":105,"q":3336,"a":3337},"antipattern-return-null","Why should a method that returns Optional never return null?","Returning `null` from a method declared to return `Optional\u003CT>` is the worst of\nboth worlds: the caller trusts the contract and writes `result.map(...)`, which\nthen throws a **`NullPointerException`** — the very thing `Optional` exists to\nprevent.\n\n```java\n\u002F\u002F broken — defeats the entire purpose\nOptional\u003CUser> find(String id) {\n    if (id == null) return null;   \u002F\u002F NEVER do this\n    ...\n}\n\n\u002F\u002F correct — empty means \"no value\"\nOptional\u003CUser> find(String id) {\n    if (id == null) return Optional.empty();\n    return Optional.ofNullable(lookup(id));\n}\n```\n\nAn `Optional` reference itself should **always be non-null**. \"No value\" is\n`Optional.empty()`, never a `null` `Optional`.\n",{"id":3339,"difficulty":126,"q":3340,"a":3341},"optional-not-serializable","Is Optional serializable, and why does that matter?","No — `Optional` does **not** implement `Serializable`, and this was a deliberate\ndesign decision to discourage using it as a **field**. A class with an\n`Optional` field can't be Java-serialized, and many frameworks (JPA entities,\nsome DTO mappers) choke on it too.\n\n```java\nclass Account implements Serializable {\n    private Optional\u003CString> email;   \u002F\u002F breaks serialization!\n}\n```\n\nIf you need a persisted or serialized \"maybe\" field, store a plain **nullable**\ntype and expose an `Optional` from the **getter** instead:\n\n```java\nprivate String email;                 \u002F\u002F serializable, may be null\npublic Optional\u003CString> getEmail() { return Optional.ofNullable(email); }\n```\n",{"id":3343,"difficulty":105,"q":3344,"a":3345},"optional-performance","What is the performance cost of Optional?","Each `Optional` is a **separate heap object** wrapping your value, so it adds an\nallocation and a layer of indirection. For a method return that's negligible,\nbut in **hot loops** or **per-element** stream work it creates real GC pressure.\n\n```java\n\u002F\u002F fine: one Optional per call\nOptional\u003CUser> u = find(id);\n\n\u002F\u002F wasteful: millions of throwaway Optionals in a tight loop\nfor (int i = 0; i \u003C 10_000_000; i++) {\n    Optional.of(i).map(x -> x + 1).get();   \u002F\u002F avoid in hot paths\n}\n```\n\nFor primitive results, the `OptionalInt`\u002F`OptionalLong`\u002F`OptionalDouble`\nspecializations skip boxing. **Rule of thumb:** use `Optional` for clear,\noccasional return values — not as a per-element data structure in performance\ncritical code.\n",{"description":103},"Java Optional interview questions — what Optional is and why, creating and consuming Optionals, map\u002FflatMap\u002Ffilter, orElse vs orElseGet vs orElseThrow, and Optional anti-patterns.","java\u002Fstreams-functional\u002Foptional","EiK2hjWl-S0dLiqYXPIZML5kP0RXUtlzfBsEx8lidyM",{"id":3351,"title":3352,"body":3353,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":3357,"navigation":108,"order":11,"path":3358,"questions":3359,"questionsCount":1764,"related":250,"seo":3436,"seoDescription":3437,"stem":3438,"subtopic":3439,"topic":46,"topicSlug":48,"updated":809,"__hash__":3440},"qa\u002Fjava\u002Fcollections\u002Fcomparable-comparator.md","Comparable Comparator",{"type":100,"value":3354,"toc":3355},[],{"title":103,"searchDepth":29,"depth":29,"links":3356},[],{},"\u002Fjava\u002Fcollections\u002Fcomparable-comparator",[3360,3362,3366,3370,3374,3378,3382,3386,3390,3394,3398,3402,3405,3409,3413,3416,3420,3424,3428,3432],{"id":150,"difficulty":113,"q":151,"a":3361},"**`Comparable\u003CT>`** defines a type's **natural ordering** from the inside: the\nclass implements it and supplies a single `compareTo(T other)` method. It lives\nin **`java.lang`**. **`Comparator\u003CT>`** defines an **external, custom ordering**\nin a separate object via `compare(T a, T b)`; it lives in **`java.util`**.\n\n| | `Comparable\u003CT>` | `Comparator\u003CT>` |\n| -- | -- | -- |\n| Package | `java.lang` | `java.util` |\n| Method | `int compareTo(T o)` | `int compare(T a, T b)` |\n| Where | implemented **by** the class | a **separate** object |\n| Orderings | one (the natural one) | as many as you like |\n| Modifies class? | yes | no |\n\nRule of thumb: use **`Comparable`** for the one obvious ordering a type *is*\n(numbers by value, strings alphabetically), and **`Comparator`** for everything\nelse — especially for types you can't edit.\n",{"id":3363,"difficulty":113,"q":3364,"a":3365},"comparable-implementation","How do you make a class sortable with Comparable?","Implement `Comparable\u003CYourType>` and override **`compareTo`** to return a\nnegative int, zero, or a positive int when `this` is less than, equal to, or\ngreater than the argument.\n\n```java\nclass Person implements Comparable\u003CPerson> {\n  String name; int age;\n  @Override public int compareTo(Person other) {\n    return Integer.compare(this.age, other.age); \u002F\u002F natural order = by age\n  }\n}\n```\n\nOnce a type is `Comparable`, it works automatically with `Collections.sort`,\n`Arrays.sort`, `TreeSet`, `TreeMap`, and `Stream.sorted()` **without** a\ncomparator argument. Rule of thumb: parameterize the interface\n(`Comparable\u003CPerson>`), never the raw `Comparable`.\n",{"id":3367,"difficulty":105,"q":3368,"a":3369},"compareto-contract","What is the contract of compareTo \u002F compare?","The return value's **sign** is what matters, not its magnitude: **negative** if\nthe first argument sorts before the second, **zero** if equal, **positive** if\nafter. The relation must be:\n\n- **Antisymmetric** — `sgn(a.compareTo(b)) == -sgn(b.compareTo(a))`.\n- **Transitive** — if `a > b` and `b > c`, then `a > c`.\n- **Consistent** — equal inputs always give equal results.\n\n```java\nInteger.compare(3, 5);   \u002F\u002F negative (any negative int)\nInteger.compare(5, 5);   \u002F\u002F 0\nInteger.compare(7, 2);   \u002F\u002F positive\n```\n\nBreaking the contract (e.g. an ordering that isn't transitive) can make\n`Arrays.sort` throw `IllegalArgumentException: Comparison method violates its\ngeneral contract!`. Rule of thumb: define order, then never break transitivity.\n",{"id":3371,"difficulty":126,"q":3372,"a":3373},"int-overflow-trap","Why is \"return a - b;\" a bad way to implement a comparator?","Subtraction can **overflow**. If `a` is large positive and `b` is large\nnegative, `a - b` wraps past `Integer.MAX_VALUE` and becomes negative — so a\nvalue that should sort *after* sorts *before*, silently corrupting the order.\n\n```java\nint a = Integer.MAX_VALUE, b = -1;\nSystem.out.println(a - b);            \u002F\u002F -2147483648  (wrong sign!)\nSystem.out.println(Integer.compare(a, b)); \u002F\u002F positive (correct)\n```\n\nThe fix is **`Integer.compare(a, b)`** (or `Long.compare`, `Double.compare`),\nwhich is overflow-safe and reads clearly. Rule of thumb: never subtract to\ncompare — always use the `compare` static helpers.\n",{"id":3375,"difficulty":105,"q":3376,"a":3377},"comparator-comparing","How does Comparator.comparing build a comparator from a key?","`Comparator.comparing(keyExtractor)` takes a function that pulls a\n**`Comparable` sort key** out of each element and returns a comparator that\norders by that key — no boilerplate `compare` body needed.\n\n```java\nList\u003CPerson> people = ...;\npeople.sort(Comparator.comparing(Person::getName));   \u002F\u002F by name\npeople.sort(Comparator.comparing(Person::getAge));    \u002F\u002F by age\n```\n\nThe extracted key (`getName`, `getAge`) must itself be `Comparable`, or you pass\na second argument: `comparing(Person::getCity, String.CASE_INSENSITIVE_ORDER)`.\nRule of thumb: prefer `comparing(...)` with a method reference over a hand-written\nlambda — it's shorter and reads like the sort you mean.\n",{"id":3379,"difficulty":105,"q":3380,"a":3381},"thencomparing","How do you sort by multiple fields with thenComparing?","Chain **`thenComparing`** after `comparing`. It acts as a **tie-breaker**: the\nnext comparator is consulted only when the previous one returns zero.\n\n```java\npeople.sort(\n  Comparator.comparing(Person::getLastName)\n            .thenComparing(Person::getFirstName)\n            .thenComparingInt(Person::getAge)   \u002F\u002F primitive, no boxing\n);\n```\n\nYou can chain as many levels as you need; each runs only on ties from the level\nabove. Rule of thumb: list your sort keys in priority order, `comparing` first\nand `thenComparing` for each subsequent tie-breaker.\n",{"id":3383,"difficulty":113,"q":3384,"a":3385},"reversed","How do you reverse a comparator's order?","Call **`.reversed()`** on any comparator to flip its direction, or use\n`Comparator.reverseOrder()` for the reverse of natural ordering.\n\n```java\npeople.sort(Comparator.comparing(Person::getAge).reversed()); \u002F\u002F oldest first\nList\u003CInteger> nums = ...;\nnums.sort(Comparator.reverseOrder());      \u002F\u002F descending naturals\nnums.sort(Collections.reverseOrder());     \u002F\u002F same idea, older API\n```\n\nWatch the **placement** with chains: `reversed()` reverses the **entire**\ncomparator built so far, not just the last `thenComparing`. To reverse only one\nfield, reverse that key: `thenComparing(Person::getAge, reverseOrder())`. Rule of\nthumb: parenthesize your chain so you know exactly what `reversed()` flips.\n",{"id":3387,"difficulty":113,"q":3388,"a":3389},"natural-reverse-order","What do Comparator.naturalOrder and reverseOrder return?","**`Comparator.naturalOrder()`** returns a comparator that uses each element's own\n`compareTo` (its natural ordering); **`reverseOrder()`** returns the inverse.\nBoth work on any `Comparable` type.\n\n```java\nList\u003CString> s = new ArrayList\u003C>(List.of(\"b\", \"a\", \"c\"));\ns.sort(Comparator.naturalOrder());   \u002F\u002F [a, b, c]\ns.sort(Comparator.reverseOrder());   \u002F\u002F [c, b, a]\n```\n\nThey're most useful as **arguments** to other methods — e.g. as the key\ncomparator in `comparing(...)` or the inner comparator of `nullsFirst(...)`.\nRule of thumb: reach for `naturalOrder()`\u002F`reverseOrder()` instead of writing\n`(a, b) -> a.compareTo(b)` by hand.\n",{"id":3391,"difficulty":105,"q":3392,"a":3393},"nulls-first-last","How do you handle null values when sorting?","A plain comparator throws **`NullPointerException`** on `null` elements. Wrap it\nwith **`Comparator.nullsFirst(...)`** or **`nullsLast(...)`** to decide where\nnulls land.\n\n```java\nList\u003CString> s = Arrays.asList(\"b\", null, \"a\");\ns.sort(Comparator.nullsFirst(Comparator.naturalOrder())); \u002F\u002F [null, a, b]\ns.sort(Comparator.nullsLast(Comparator.naturalOrder()));  \u002F\u002F [a, b, null]\n```\n\nIt also guards a **null key** in a chain:\n`comparing(Person::getName, nullsLast(naturalOrder()))`. Rule of thumb: if a\nfield can be `null`, wrap its comparator in `nullsFirst`\u002F`nullsLast` rather than\nhoping the data is clean.\n",{"id":3395,"difficulty":105,"q":3396,"a":3397},"comparingint-boxing","Why use comparingInt \u002F comparingLong \u002F comparingDouble?","The generic `comparing(...)` returns a key of type `Comparable`, which means an\n`int` key gets **autoboxed** to `Integer` on every comparison. The primitive\nspecializations **`comparingInt`**, **`comparingLong`**, and **`comparingDouble`**\ntake a primitive-returning extractor and avoid that boxing.\n\n```java\n\u002F\u002F boxes each age to Integer\npeople.sort(Comparator.comparing(Person::getAge));\n\u002F\u002F no boxing — faster in hot paths\npeople.sort(Comparator.comparingInt(Person::getAge));\n```\n\nSame applies to the chained form: prefer `thenComparingInt`. Rule of thumb: when\nthe sort key is a primitive, use the `comparingInt\u002FLong\u002FDouble` variant.\n",{"id":3399,"difficulty":113,"q":3400,"a":3401},"collections-sort","What is the difference between Collections.sort and List.sort?","Both sort a `List` in place. **`Collections.sort(list)`** is the older static\nhelper; **`list.sort(comparator)`** is a default method added to `List` in Java\n8 and is the modern idiom. Functionally they do the same thing.\n\n```java\nCollections.sort(list);                       \u002F\u002F natural order\nCollections.sort(list, comparator);           \u002F\u002F custom\nlist.sort(null);                              \u002F\u002F null == natural order\nlist.sort(Comparator.comparing(Person::getAge));\n```\n\n`Collections.sort` actually delegates to `list.sort` under the hood. Passing\n`null` as the comparator means \"use natural ordering\" (the elements must be\n`Comparable`). Rule of thumb: prefer `list.sort(...)` — it's the method on the\nobject you already have.\n",{"id":2372,"difficulty":113,"q":3403,"a":3404},"How does Arrays.sort work with comparators?","`Arrays.sort` sorts an **array**. For an **object** array you can pass a\ncomparator; for **primitive** arrays you cannot (only natural ascending order is\nsupported).\n\n```java\nInteger[] boxed = {3, 1, 2};\nArrays.sort(boxed, Comparator.reverseOrder()); \u002F\u002F [3, 2, 1] — needs Integer[]\n\nint[] prims = {3, 1, 2};\nArrays.sort(prims);                            \u002F\u002F [1, 2, 3] only — no comparator\n```\n\nTo sort primitives descending you must box to `Integer[]`, or sort ascending and\nreverse manually. Rule of thumb: comparators need object arrays; primitive\n`Arrays.sort` is natural-order only.\n",{"id":3406,"difficulty":113,"q":3407,"a":3408},"stream-sorted","How do you sort a stream?","`Stream.sorted()` sorts by **natural ordering** (elements must be `Comparable`);\n`Stream.sorted(comparator)` sorts by a custom order. It's an intermediate\noperation that returns a new, sorted stream.\n\n```java\nList\u003CPerson> byAge = people.stream()\n    .sorted(Comparator.comparingInt(Person::getAge))\n    .collect(Collectors.toList());\n```\n\nUnlike `list.sort`, this does **not** mutate the source — it produces a new\nordering downstream. `sorted()` is also **stateful**: it must buffer all elements\nbefore emitting any. Rule of thumb: use stream `sorted` when you're already in a\npipeline and want a new collection, not an in-place sort.\n",{"id":3410,"difficulty":105,"q":3411,"a":3412},"treemap-treeset-comparator","How do TreeMap and TreeSet use a comparator?","`TreeMap` and `TreeSet` keep elements **sorted**. By default they use the\nelements' natural ordering (`Comparable`), but you can pass a `Comparator` to the\nconstructor to control the order — and to allow non-`Comparable` types.\n\n```java\nTreeSet\u003CString> ci = new TreeSet\u003C>(String.CASE_INSENSITIVE_ORDER);\nci.add(\"Bravo\"); ci.add(\"alpha\");   \u002F\u002F sorted case-insensitively\n\nTreeMap\u003CPerson, String> m =\n    new TreeMap\u003C>(Comparator.comparing(Person::getName));\n```\n\nThe comparator is fixed at construction and used for **every** ordering and\nlookup operation. Rule of thumb: supply a comparator when the natural order isn't\nwhat you want — or when the key type isn't `Comparable` at all.\n",{"id":2887,"difficulty":105,"q":3414,"a":3415},"How does a PriorityQueue use a comparator?","A `PriorityQueue` is a **min-heap** by default — `poll()` returns the\n**smallest** element per natural ordering. Pass a comparator to change what\n\"smallest\" means, e.g. to build a max-heap.\n\n```java\nPriorityQueue\u003CInteger> min = new PriorityQueue\u003C>();              \u002F\u002F 1 first\nPriorityQueue\u003CInteger> max =\n    new PriorityQueue\u003C>(Comparator.reverseOrder());              \u002F\u002F largest first\nPriorityQueue\u003CPerson> byAge =\n    new PriorityQueue\u003C>(Comparator.comparingInt(Person::getAge));\n```\n\nThe heap only guarantees the **head** is the min\u002Fmax — iterating the queue does\n**not** yield sorted order. Rule of thumb: pass `reverseOrder()` for a max-heap,\nand only trust `peek`\u002F`poll`, never iteration order.\n",{"id":3417,"difficulty":126,"q":3418,"a":3419},"consistent-with-equals","What does \"consistent with equals\" mean for compareTo?","An ordering is **consistent with equals** when `a.compareTo(b) == 0` exactly\nwhen `a.equals(b)` is true. It's strongly **recommended** but not required — and\nviolating it breaks sorted collections like `TreeSet`\u002F`TreeMap`, which judge\nequality by `compareTo`, not `equals`.\n\n```java\n\u002F\u002F BigDecimal is the classic inconsistency:\nnew BigDecimal(\"1.0\").equals(new BigDecimal(\"1.00\"));     \u002F\u002F false\nnew BigDecimal(\"1.0\").compareTo(new BigDecimal(\"1.00\"));  \u002F\u002F 0  -> \"equal\"\n```\n\nSo a `TreeSet\u003CBigDecimal>` treats `1.0` and `1.00` as the **same** element, while\na `HashSet` treats them as distinct. Rule of thumb: keep `compareTo` consistent\nwith `equals` unless you have a specific reason, and document it when you don't.\n",{"id":3421,"difficulty":126,"q":3422,"a":3423},"treeset-dedup-compareto","Why does TreeSet use compareTo instead of equals to detect duplicates?","A `TreeSet` is backed by a balanced tree, so it locates and de-duplicates\nelements purely by **comparison**: if `compareTo`\u002F`compare` returns **0**, the\nelement is considered a **duplicate** and is rejected — `equals` and `hashCode`\nare never consulted.\n\n```java\n\u002F\u002F comparator looks only at age:\nTreeSet\u003CPerson> set = new TreeSet\u003C>(Comparator.comparingInt(Person::getAge));\nset.add(new Person(\"Ada\", 30));\nset.add(new Person(\"Bob\", 30));   \u002F\u002F NOT added — same age -> compare == 0\nSystem.out.println(set.size());   \u002F\u002F 1\n```\n\nThis surprises people: two objects that aren't `equals` can still collide in a\n`TreeSet` if the comparator rates them equal. Rule of thumb: make the\n`TreeSet`\u002F`TreeMap` comparator total enough that only truly-equal elements\ncompare to 0.\n",{"id":3425,"difficulty":105,"q":3426,"a":3427},"sort-stability","What is a stable sort and which Java sorts are stable?","A **stable** sort preserves the relative order of elements that compare as\n**equal**. This matters when you sort by multiple keys in passes, or want ties to\nkeep their original sequence.\n\n```java\n\u002F\u002F sort by city, then (stably) by name keeps city groups intact\npeople.sort(Comparator.comparing(Person::getName));\npeople.sort(Comparator.comparing(Person::getCity)); \u002F\u002F ties stay name-ordered\n```\n\n`Collections.sort`, `List.sort`, and `Arrays.sort` on **objects** (TimSort) are\n**guaranteed stable**. `Arrays.sort` on **primitives** uses a dual-pivot\nquicksort and is **not** stable (irrelevant for primitives, since equal ints are\nindistinguishable). Rule of thumb: rely on stability only for object sorts.\n",{"id":3429,"difficulty":113,"q":3430,"a":3431},"lambda-vs-method-ref","How do lambdas and method references express comparators?","`Comparator\u003CT>` is a **functional interface** (one abstract method, `compare`),\nso you can write it as a lambda or, more cleanly, build it with the factory\nmethods and method references.\n\n```java\n\u002F\u002F verbose lambda\nComparator\u003CPerson> c1 = (a, b) -> a.getName().compareTo(b.getName());\n\u002F\u002F factory + method reference — preferred\nComparator\u003CPerson> c2 = Comparator.comparing(Person::getName);\n```\n\nThe factory form is shorter, harder to get wrong (no manual `compareTo`), and\ncomposes with `thenComparing`\u002F`reversed`. Rule of thumb: reserve raw `(a, b) ->`\nlambdas for genuinely custom logic; use `Comparator.comparing(...)` for the\ncommon \"sort by a field\" case.\n",{"id":3433,"difficulty":105,"q":3434,"a":3435},"comparator-reuse","Should you store comparators as constants and reuse them?","Comparators are typically **stateless and thread-safe**, so the idiom is to build\none once as a `static final` constant and reuse it everywhere rather than\nre-creating it on every sort.\n\n```java\npublic static final Comparator\u003CPerson> BY_NAME_THEN_AGE =\n    Comparator.comparing(Person::getLastName)\n              .thenComparing(Person::getFirstName)\n              .thenComparingInt(Person::getAge);\n\npeople.sort(BY_NAME_THEN_AGE);\n```\n\nA named constant documents the ordering, avoids rebuilding the chain in hot\nloops, and can be shared across `TreeSet`, `PriorityQueue`, and `sort` calls.\nRule of thumb: name and cache the comparators you use more than once.\n",{"description":103},"Java Comparable and Comparator interview questions — natural vs custom ordering, compareTo vs compare, comparator chaining and reversal, sorting collections, and consistency with equals.","java\u002Fcollections\u002Fcomparable-comparator","Comparable & Comparator","gILDt_5jcrQdvGndx3dEU40Jk25bFoZCd1lxPrI2iDU",{"id":3442,"title":3443,"body":3444,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":3448,"navigation":108,"order":11,"path":3449,"questions":3450,"questionsCount":1764,"related":250,"seo":3528,"seoDescription":3529,"stem":3530,"subtopic":3531,"topic":72,"topicSlug":74,"updated":809,"__hash__":3532},"qa\u002Fjava\u002Fconcurrency\u002Fvolatile-memory-model.md","Volatile Memory Model",{"type":100,"value":3445,"toc":3446},[],{"title":103,"searchDepth":29,"depth":29,"links":3447},[],{},"\u002Fjava\u002Fconcurrency\u002Fvolatile-memory-model",[3451,3455,3459,3462,3465,3469,3473,3477,3481,3485,3489,3492,3496,3500,3504,3508,3512,3516,3520,3524],{"id":3452,"difficulty":105,"q":3453,"a":3454},"visibility-problem","What is the visibility problem in multithreaded Java?","Without synchronization, there is **no guarantee** that a write made by one\nthread becomes visible to another. Each thread may keep a value in a **CPU\nregister or cache**, or the compiler may hoist a field read out of a loop, so a\nthread can read a **stale** copy forever.\n\n```java\nclass Worker {\n  boolean stop = false;   \u002F\u002F NOT volatile\n\n  void run() {\n    while (!stop) { }     \u002F\u002F may loop FOREVER — stop is cached\n  }\n  void shutdown() { stop = true; } \u002F\u002F another thread sets it\n}\n```\n\nThe `while (!stop)` loop can spin indefinitely even after `shutdown()` runs,\nbecause the reading thread never re-reads `stop` from main memory. Marking\n`stop` **`volatile`** fixes it. This is the canonical motivation for both\n`volatile` and the Java Memory Model.\n",{"id":3456,"difficulty":126,"q":3457,"a":3458},"what-is-jmm","What is the Java Memory Model and why does it exist?","The **Java Memory Model (JMM)** is the part of the language spec that defines\n**which writes a thread is guaranteed to see** and **what reorderings are\nlegal**. It exists because real hardware and compilers aggressively optimize —\nCPU caches, store buffers, out-of-order execution, and JIT reordering — so\nwithout rules, multithreaded behavior would differ per CPU and be impossible to\nreason about.\n\nThe JMM defines an abstract relation called **happens-before**: if action A\nhappens-before action B, then A's effects are visible to B. Anything *not*\nordered by happens-before may be reordered or seen stale. So the JMM doesn't\npromise a single global order of operations — it promises a **minimum set of\nguarantees** (via `volatile`, `synchronized`, `final`, thread start\u002Fjoin) that\nportable concurrent code can rely on across JVMs and hardware.\n",{"id":1305,"difficulty":126,"q":3460,"a":3461},"What is the happens-before relationship?","**Happens-before** is the JMM's ordering guarantee: if A *happens-before* B, then\neverything A wrote is visible to B, and A appears to execute before B. The main\nsources of happens-before edges are:\n\n| Rule | Edge |\n| ---- | ---- |\n| **Program order** | each action happens-before later actions *in the same thread* |\n| **Monitor lock** | unlocking a monitor happens-before a later lock of the *same* monitor |\n| **Volatile** | a write to a volatile field happens-before every later read of it |\n| **Thread start** | `t.start()` happens-before any action in the started thread |\n| **Thread join** | every action in a thread happens-before another thread's `t.join()` return |\n| **Transitivity** | if A hb B and B hb C, then A hb C |\n\nWithout a happens-before edge between two threads' actions, the JMM gives **no\nvisibility or ordering guarantee** — that's the heart of every concurrency bug.\n",{"id":3463,"difficulty":105,"q":3089,"a":3464},"volatile-guarantees","`volatile` provides two things: **visibility** and **ordering**. A write to a\nvolatile field is immediately flushed so it's visible to every thread, and a\nread always fetches the latest value from main memory (never a cached copy). It\nalso establishes a **happens-before** edge: a volatile write happens-before any\nlater volatile read of that field.\n\n```java\nvolatile boolean ready = false;\nint data;\n\n\u002F\u002F writer thread\ndata = 42;          \u002F\u002F ordinary write\nready = true;       \u002F\u002F volatile write — publishes data too\n\n\u002F\u002F reader thread\nif (ready) {        \u002F\u002F volatile read\n  use(data);        \u002F\u002F guaranteed to see 42\n}\n```\n\nBecause the volatile write of `ready` happens-before the read, the *ordinary*\nwrite to `data` that preceded it is also visible. **Rule of thumb:** `volatile`\nmakes a single field a safe, lock-free flag — and piggybacks the writes before\nit.\n",{"id":3466,"difficulty":126,"q":3467,"a":3468},"volatile-not-atomic","Why doesn't volatile make count++ thread-safe?","Because `volatile` guarantees **visibility, not atomicity**, and `count++` is a\n**compound action**: read, add one, write back. Two threads can both read the\nsame value, both increment it, and both write back the same result — a lost\nupdate — even though every individual read and write sees fresh memory.\n\n```java\nvolatile int count = 0;\ncount++;   \u002F\u002F really: int tmp = count; tmp = tmp + 1; count = tmp;\n```\n\nVolatile makes each step visible but does **not** make the three steps\nindivisible. For atomic counters use **`AtomicInteger`** (`incrementAndGet()`),\nor guard the update with a lock. **Rule of thumb:** `volatile` is correct only\nwhen a write doesn't depend on the current value (e.g. a flag), never for\nread-modify-write.\n",{"id":3470,"difficulty":126,"q":3471,"a":3472},"volatile-vs-synchronized","What is the difference between volatile and synchronized?","Both establish happens-before edges and fix visibility, but they solve different\nproblems:\n\n| | `volatile` | `synchronized` |\n| --- | --- | --- |\n| **Visibility** | yes (per field) | yes |\n| **Atomicity** | no | yes (the whole block) |\n| **Mutual exclusion** | no | yes — one thread at a time |\n| **Blocking** | never blocks | can block on the lock |\n| **Scope** | a single field | a block \u002F method |\n\n```java\nvolatile boolean flag;          \u002F\u002F cheap visibility for one flag\n\nsynchronized (lock) {           \u002F\u002F exclusive access + visibility\n  balance = balance - amount;   \u002F\u002F compound action made safe\n}\n```\n\nUse `volatile` when you only need one variable's *latest value* visible. Use\n`synchronized` when you need **atomic compound operations** or to protect\n**multiple related fields** together.\n",{"id":3474,"difficulty":126,"q":3475,"a":3476},"atomicity-visibility-ordering","What is the difference between atomicity, visibility, and ordering?","These are three **distinct** concurrency concerns, and interviewers love\nseparating them:\n\n- **Atomicity** — an operation happens completely or not at all; no other thread\n  sees a half-finished state. `count++` is *not* atomic.\n- **Visibility** — a write by one thread becomes observable to another. Without\n  synchronization, writes may stay invisible (cached) indefinitely.\n- **Ordering** — the order in which operations appear to execute. Compilers and\n  CPUs may **reorder** instructions that lack a happens-before constraint.\n\n```java\nvolatile boolean v;   \u002F\u002F gives visibility + ordering, NOT atomicity\nsynchronized(l){...}   \u002F\u002F gives all three for the guarded region\n```\n\n`volatile` covers visibility and ordering; **only** locks (or atomic classes)\nadd atomicity. Picking the wrong tool because you conflated these is the classic\nmistake.\n",{"id":3478,"difficulty":126,"q":3479,"a":3480},"instruction-reordering","What is instruction reordering and why is it allowed?","Compilers, the JIT, and CPUs may **execute instructions in a different order**\nthan written, as long as a *single thread's* result is unchanged. It's allowed\nbecause reordering enables huge optimizations (register allocation, hiding memory\nlatency, out-of-order execution).\n\n```java\nint a = 1;   \u002F\u002F these two have no dependency,\nint b = 2;   \u002F\u002F so they may be reordered freely\n```\n\nThe catch: reorderings that are invisible within one thread can be **very\nvisible to another thread**. A second thread might observe `b` set before `a`.\nThe JMM only forbids reordering across **happens-before** edges (volatile\naccesses, lock release\u002Facquire). **Rule of thumb:** within a thread you never\nnotice reordering; across threads you must create a happens-before edge to\nconstrain it.\n",{"id":3482,"difficulty":105,"q":3483,"a":3484},"as-if-serial","What is the as-if-serial \u002F single-thread guarantee?","The **as-if-serial** semantics promise that within a **single thread**, the\nprogram behaves *as if* its statements ran in exact source order — regardless of\nhow the compiler or CPU actually reordered them. Dependencies are always\nrespected.\n\n```java\nint x = 5;\nint y = x + 1;   \u002F\u002F depends on x — can never be reordered before it\nSystem.out.println(y); \u002F\u002F always 6, no matter the optimizations\n```\n\nSo a sequential program never has to worry about reordering. The guarantee\n**only** covers one thread in isolation; the moment another thread observes the\nsame fields, as-if-serial says nothing, and you need happens-before edges. This\nis why correct single-threaded code can still be broken when shared across\nthreads.\n",{"id":3486,"difficulty":105,"q":3487,"a":3488},"volatile-flag-pattern","What is the volatile flag pattern?","The most common correct use of `volatile`: a **one-way status flag** that one\nthread sets and others poll. Because the write\u002Fread of the flag is volatile, the\nchange is guaranteed visible, so the polling thread eventually stops.\n\n```java\nclass Service {\n  private volatile boolean running = true;\n\n  void serve() {\n    while (running) { doWork(); }   \u002F\u002F sees running=false promptly\n  }\n  void stop() { running = false; }  \u002F\u002F called from another thread\n}\n```\n\nThis works only because the operation is a **simple assignment**, not a\ncompound update, and no other shared state needs to change atomically with it.\n**Rule of thumb:** reach for the volatile flag for cancellation\u002Fshutdown\nsignals — and nothing that requires read-modify-write.\n",{"id":388,"difficulty":126,"q":3490,"a":3491},"Why does the double-checked-locking singleton need volatile?","Double-checked locking checks the instance twice — once without a lock, once\ninside — to avoid synchronizing on every call. Without `volatile` it is\n**broken** because `instance = new Singleton()` is not atomic: it allocates\nmemory, runs the constructor, and assigns the reference, and those steps can be\n**reordered**. Another thread could see a non-null reference to a\n*partially-constructed* object.\n\n```java\nclass Singleton {\n  private static volatile Singleton instance;   \u002F\u002F volatile is REQUIRED\n\n  static Singleton get() {\n    if (instance == null) {                 \u002F\u002F 1st check, no lock\n      synchronized (Singleton.class) {\n        if (instance == null)               \u002F\u002F 2nd check, locked\n          instance = new Singleton();       \u002F\u002F safe publish via volatile\n      }\n    }\n    return instance;\n  }\n}\n```\n\n`volatile` forbids the reordering and adds a happens-before edge, so a reader\nthat sees the reference also sees a fully built object. **Rule of thumb:** if you\nhand-write DCL, the field *must* be volatile (or just use a holder-class\nidiom instead).\n",{"id":3493,"difficulty":126,"q":3494,"a":3495},"safe-publication","What is safe publication and how do you achieve it?","**Publishing** an object means making it visible to other threads;\n**safe publication** ensures that when another thread sees the reference, it also\nsees the object's fully-initialized state. Just storing a reference in a shared\nfield is *unsafe* — another thread may see the reference but stale field values.\n\nSafe ways to publish, per *Java Concurrency in Practice*:\n\n- Store it in a **`volatile`** field (or `AtomicReference`).\n- Store it in a **`final`** field set in a constructor.\n- Store it into a field guarded by a **lock**.\n- Initialize it from a **static initializer**.\n\n```java\nclass Holder {\n  private volatile Config config;          \u002F\u002F safe publication\n  void set(Config c) { config = c; }       \u002F\u002F readers see a complete Config\n}\n```\n\n**Rule of thumb:** never just assign a shared object to a plain field and hope —\nroute the publication through volatile, final, a lock, or a thread-safe\ncollection.\n",{"id":3497,"difficulty":126,"q":3498,"a":3499},"final-field-freeze","What guarantees do final fields provide across threads?","`final` fields have special **freeze semantics**: when a constructor finishes,\nall `final` fields are \"frozen\", and any thread that obtains the object through a\nreference published *after* construction is guaranteed to see their correctly\ninitialized values — **without** additional synchronization.\n\n```java\nclass Point {\n  final int x, y;                 \u002F\u002F frozen at end of constructor\n  Point(int x, int y) { this.x = x; this.y = y; }\n}\n\u002F\u002F any thread seeing a Point always sees the real x and y\n```\n\nThe one caveat: this holds only if the object **doesn't leak `this`** during\nconstruction (e.g. registering a listener before the constructor returns). Final\nfields are why **immutable objects are inherently thread-safe** and can be shared\nfreely. **Rule of thumb:** make fields `final` and the object immutable, and you\nget safe sharing for free.\n",{"id":3501,"difficulty":126,"q":3502,"a":3503},"long-double-tearing","Why can reads and writes of long and double be non-atomic?","The JMM only guarantees that reads and writes of **32-bit-or-smaller** types and\n**references** are atomic. A non-volatile `long` or `double` (64 bits) may be\nwritten as **two separate 32-bit stores**, so another thread can observe a\n**torn** value — the high half of one write combined with the low half of\nanother.\n\n```java\nlong balance;            \u002F\u002F NOT volatile — write may tear\n\u002F\u002F Thread A: balance = 0xFFFFFFFF00000000L;\n\u002F\u002F Thread B might read 0xFFFFFFFF00000000, 0x0, or a mix\n```\n\nDeclaring the field **`volatile`** makes 64-bit reads and writes atomic (and\nvisible). In practice most 64-bit JVMs write longs atomically anyway, but the\nspec doesn't require it, so portable code must use `volatile` or a lock.\n**Rule of thumb:** shared `long`\u002F`double` that multiple threads write should be\n`volatile` (or atomic) to avoid tearing.\n",{"id":3505,"difficulty":126,"q":3506,"a":3507},"memory-barriers","What are memory barriers (fences) and how do they relate to volatile?","A **memory barrier** (or fence) is a low-level CPU\u002Fcompiler instruction that\nrestricts reordering and forces cached writes to be flushed or invalidated. The\nJMM is the *abstract* model; barriers are *how* the JVM actually implements it on\nhardware.\n\nA `volatile` access compiles to barriers around it:\n\n- A **volatile write** is preceded by a *StoreStore* barrier and followed by a\n  *StoreLoad* barrier — earlier writes can't move after it, and the write is\n  flushed.\n- A **volatile read** is followed by *LoadLoad* \u002F *LoadStore* barriers — later\n  reads can't move before it.\n\n```java\nx = 1;            \u002F\u002F ordinary write\nvolatileFlag = 2; \u002F\u002F StoreStore before, StoreLoad after — x can't cross down\n```\n\nYou almost never write barriers directly in Java (they're exposed via\n`VarHandle`); `volatile` and `synchronized` insert the right ones for you.\n",{"id":3509,"difficulty":126,"q":3510,"a":3511},"volatile-array","Does declaring an array volatile make its elements volatile?","No. `volatile` on an **array reference** only makes the **reference** itself\nvolatile — reassigning the whole array is visible. Reads and writes of individual\n**elements** are *not* volatile and carry no visibility guarantee.\n\n```java\nvolatile int[] arr = new int[10];\narr = new int[20];   \u002F\u002F volatile: visible to other threads\narr[3] = 99;         \u002F\u002F NOT volatile — element write may be invisible\n```\n\nTo get volatile-element semantics, use **`AtomicIntegerArray`** \u002F\n`AtomicReferenceArray`, or access elements through a `VarHandle` with the right\naccess mode. **Rule of thumb:** a volatile array gives you a safe *swap* of the\narray, not safe concurrent *element* updates.\n",{"id":3513,"difficulty":126,"q":3514,"a":3515},"volatile-compound-state","Why doesn't making fields volatile make a multi-field invariant safe?","`volatile` operates on **one field at a time**, so it can't keep **two related\nfields consistent** with each other. Even if both are volatile, another thread\ncan observe an update to one field but not yet the other, breaking the invariant.\n\n```java\nclass Range {\n  private volatile int lower = 0, upper = 10;   \u002F\u002F both volatile\n  void setLower(int v) {\n    if (v > upper) throw new IllegalArgumentException();\n    lower = v;     \u002F\u002F check-then-act: not atomic across two fields\n  }\n}\n```\n\nTwo threads calling `setLower`\u002F`setUpper` concurrently can pass the checks and\nleave `lower > upper`. Multi-field invariants need a **lock** (or an immutable\nobject swapped atomically). **Rule of thumb:** `volatile` is per-field; whenever\nan operation spans more than one variable, you need a lock.\n",{"id":3517,"difficulty":105,"q":3518,"a":3519},"volatile-vs-atomic","When should you use an Atomic class instead of volatile?","Use `volatile` when you only need a field's writes to be **visible** and each\noperation is an independent assignment. Use an **`Atomic`** class\n(`AtomicInteger`, `AtomicReference`, …) when you need an **atomic\nread-modify-write** — increment, compare-and-set, accumulate.\n\n```java\nvolatile boolean ready;            \u002F\u002F visibility only — fine\n\nAtomicInteger seq = new AtomicInteger();\nint id = seq.incrementAndGet();    \u002F\u002F atomic RMW — volatile can't do this\n\nAtomicReference\u003CNode> head = new AtomicReference\u003C>();\nhead.compareAndSet(old, updated);  \u002F\u002F lock-free CAS update\n```\n\nAtomic classes are built on **compare-and-swap (CAS)** hardware instructions and\ngive lock-free atomicity on a single variable. **Rule of thumb:** flag →\n`volatile`; counter\u002Faccumulator\u002FCAS → `Atomic`; multiple fields → lock.\n",{"id":3521,"difficulty":105,"q":3522,"a":3523},"synchronized-visibility","Does synchronized also provide visibility, or only mutual exclusion?","It provides **both**. People think of `synchronized` as a lock for mutual\nexclusion, but it also creates happens-before edges that guarantee visibility:\n**releasing** a monitor happens-before any subsequent **acquire** of the *same*\nmonitor. So entering a synchronized block sees all writes made before the last\nthread exited it.\n\n```java\nObject lock = new Object();\nint data;\n\nsynchronized (lock) { data = 42; }   \u002F\u002F release flushes the write\nsynchronized (lock) { use(data); }   \u002F\u002F acquire sees 42 — visibility\n```\n\nThat's why correctly synchronized code never needs `volatile` on the fields it\nguards — the lock already publishes them. The two effects (exclusion +\nvisibility) come together, but only when **both** threads synchronize on the\n**same** lock.\n",{"id":3525,"difficulty":126,"q":3526,"a":3527},"happens-before-transitivity","How does happens-before transitivity enable safe publication?","**Transitivity** — if A happens-before B and B happens-before C, then A\nhappens-before C — is what lets a single volatile or lock edge publish a whole\ncluster of ordinary writes.\n\n```java\nint a, b;                 \u002F\u002F ordinary fields\nvolatile boolean pub;\n\n\u002F\u002F Writer\na = 1;                    \u002F\u002F (1)\nb = 2;                    \u002F\u002F (2)\npub = true;               \u002F\u002F (3) volatile write\n\n\u002F\u002F Reader\nif (pub) {                \u002F\u002F (4) volatile read\n  System.out.println(a + b); \u002F\u002F sees 3\n}\n```\n\nBy program order (1) and (2) happen-before (3); the volatile rule makes (3)\nhappen-before (4); transitivity chains them so (1) and (2) are visible at (4) —\neven though `a` and `b` are plain fields. **Rule of thumb:** one happens-before\nedge carries along everything that preceded it, which is exactly how `volatile`\nand locks publish data safely.\n",{"description":103},"Java volatile and memory model interview questions — the happens-before relationship, visibility vs atomicity, the volatile keyword, instruction reordering, and safe publication.","java\u002Fconcurrency\u002Fvolatile-memory-model","volatile & Memory Model","vmCnZOWFAcHaVb_RhIjOk8II7VciU1wMqi0NATdj5wI",{"id":3534,"title":3535,"body":3536,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":3540,"navigation":108,"order":11,"path":3541,"questions":3542,"questionsCount":3181,"related":250,"seo":3591,"seoDescription":3592,"stem":3593,"subtopic":3594,"topic":90,"topicSlug":92,"updated":809,"__hash__":3595},"qa\u002Fjava\u002Fmodern-java\u002Finstanceof-pattern-matching.md","Instanceof Pattern Matching",{"type":100,"value":3537,"toc":3538},[],{"title":103,"searchDepth":29,"depth":29,"links":3539},[],{},"\u002Fjava\u002Fmodern-java\u002Finstanceof-pattern-matching",[3543,3547,3551,3555,3559,3563,3567,3571,3575,3579,3583,3587],{"id":3544,"difficulty":113,"q":3545,"a":3546},"what-is-instanceof-pattern-matching","What is pattern matching for instanceof and what problem does it solve?","**Pattern matching for `instanceof`** (Java 16, JEP 394) combines a type\ntest with a **binding variable** in a single expression, eliminating the\nredundant cast that always followed a traditional `instanceof` check.\n\n```java\n\u002F\u002F Old way — test then cast:\nif (obj instanceof String) {\n    String s = (String) obj;   \u002F\u002F redundant — we already know it's a String\n    System.out.println(s.toUpperCase());\n}\n\n\u002F\u002F Pattern matching (Java 16+):\nif (obj instanceof String s) {\n    System.out.println(s.toUpperCase()); \u002F\u002F s is bound here, no cast needed\n}\n```\n\n**Rule of thumb:** if you ever follow `instanceof` with a cast to the same\ntype on the next line, rewrite it as a pattern matching `instanceof`.\n",{"id":3548,"difficulty":105,"q":3549,"a":3550},"binding-variable-scope","What is the scope of the binding variable in instanceof pattern matching?","The binding variable is in scope only where the compiler can prove the\npattern has matched — this is called **definite assignment** based on\n**flow-sensitive typing**:\n\n```java\nObject obj = getObject();\n\nif (obj instanceof String s) {\n    System.out.println(s.length()); \u002F\u002F s in scope: pattern matched\n}\n\u002F\u002F s NOT in scope here\n\n\u002F\u002F Also works in the same condition with &&:\nif (obj instanceof String s && s.length() > 5) {\n    System.out.println(s.toUpperCase()); \u002F\u002F s in scope in both parts of &&\n}\n\n\u002F\u002F NOT in scope with ||:\n\u002F\u002F if (obj instanceof String s || s.isEmpty()) { } \u002F\u002F compile error\n```\n\n**Rule of thumb:** the binding variable is in scope in the `true` branch\nand in `&&` chains; it is NOT in scope in the `false` branch or `||` chains.\n",{"id":3552,"difficulty":105,"q":3553,"a":3554},"negation-pattern","How does instanceof pattern matching work with negation?","When you negate the pattern with `!`, the binding variable is in scope\nin the **false \u002F else branch** because that's where the match is guaranteed\nnot to hold — so the variable would be undefined there. Instead, the\nvariable is in scope after an early `return` or `throw`:\n\n```java\nvoid process(Object obj) {\n    if (!(obj instanceof String s)) {\n        throw new IllegalArgumentException(\"Expected String\");\n    }\n    \u002F\u002F s is in scope here — we know obj is a String\n    System.out.println(s.toUpperCase());\n}\n```\n\nThis pattern is useful for **guard clauses** (early return \u002F fail-fast)\nthat validate types at method entry.\n\n**Rule of thumb:** negate `instanceof` patterns for guard clauses; the\nbinding variable flows into scope after the guard exits.\n",{"id":3556,"difficulty":105,"q":3557,"a":3558},"compound-conditions","Can you combine instanceof pattern matching with other conditions?","Yes. Pattern variables work naturally with `&&` to add conditions on the\nmatched value:\n\n```java\nObject obj = getObject();\n\n\u002F\u002F Type test + length check in one expression:\nif (obj instanceof String s && s.length() > 10) {\n    System.out.println(\"long string: \" + s);\n}\n\n\u002F\u002F Type test + nullity (null never matches instanceof):\nif (obj instanceof String s) {\n    \u002F\u002F s is guaranteed non-null here — instanceof returns false for null\n}\n\n\u002F\u002F Multiple type checks in sequence:\nif (obj instanceof List\u003C?> list && !list.isEmpty()\n        && list.get(0) instanceof Integer first) {\n    System.out.println(\"First int: \" + first);\n}\n```\n\n**Rule of thumb:** chain `&&` conditions freely after an `instanceof`\npattern — the binding variable is available throughout the `&&` chain.\n",{"id":3560,"difficulty":113,"q":3561,"a":3562},"instanceof-null-behaviour","What does instanceof return for null?","**`instanceof` always returns `false` for `null`**, regardless of the\ntype being tested. This means the binding variable in a pattern matching\n`instanceof` is always non-null when the pattern matches — no explicit\nnull check needed.\n\n```java\nObject obj = null;\nSystem.out.println(obj instanceof String);   \u002F\u002F false\nSystem.out.println(obj instanceof String s); \u002F\u002F false — s never bound\n\n\u002F\u002F Traditional null check is unnecessary:\nif (obj instanceof String s) {\n    \u002F\u002F s is guaranteed non-null here\n    s.length(); \u002F\u002F safe — no NPE\n}\n```\n\n**Rule of thumb:** `instanceof` patterns implicitly handle null safely —\nthe branch is not entered for null values, so no explicit null guard is\nneeded before the pattern test.\n",{"id":3564,"difficulty":105,"q":3565,"a":3566},"pattern-variable-shadowing","Can a pattern variable shadow an existing variable?","A pattern variable can **shadow** a field or outer-scope variable but\n**cannot shadow a local variable** in the same scope:\n\n```java\nclass Processor {\n    String value = \"field\";\n\n    void process(Object obj) {\n        \u002F\u002F Shadows the field 'value' — allowed:\n        if (obj instanceof String value) {\n            System.out.println(value); \u002F\u002F refers to the pattern variable\n        }\n\n        String local = \"existing\";\n        \u002F\u002F Cannot shadow a local in the same scope — compile error:\n        \u002F\u002F if (obj instanceof String local) { }\n    }\n}\n```\n\n**Rule of thumb:** treat pattern variables like regular local variables\nfor scoping — they can shadow fields but not other locals in the same block.\n",{"id":3568,"difficulty":113,"q":3569,"a":3570},"instanceof-vs-cast","Why is the old instanceof + cast pattern considered bad practice now?","The old idiom is **redundant** — you check the type with `instanceof`,\nthen immediately cast to the same type, which the compiler already knows\nis safe:\n\n```java\n\u002F\u002F Anti-pattern — states the type twice:\nif (obj instanceof String) {\n    String s = (String) obj;  \u002F\u002F the cast cannot fail — why write it?\n    ...\n}\n\n\u002F\u002F Correct — DRY, type stated once:\nif (obj instanceof String s) {\n    ...\n}\n```\n\nBeyond redundancy, the old form is slightly error-prone — a typo could\ncast to a different type than was tested, producing a `ClassCastException`\nat runtime instead of a compile error.\n\n**Rule of thumb:** the old `instanceof` + cast is a code smell in Java 16+;\nreplace it with a pattern matching `instanceof` in any code review.\n",{"id":3572,"difficulty":105,"q":3573,"a":3574},"pattern-in-ternary","Can you use instanceof pattern matching in a ternary expression?","You can use the bound variable in the **true branch** of the ternary\nbecause the variable is only in scope where the pattern is guaranteed\nto have matched:\n\n```java\nObject obj = getValue();\n\n\u002F\u002F Binding variable in scope in the true branch:\nString result = obj instanceof String s ? s.toUpperCase() : \"not a string\";\n```\n\nThe variable `s` is not accessible in the false branch, which is correct —\nif `obj` is not a `String`, `s` would be undefined.\n\n**Rule of thumb:** pattern variables in ternaries behave exactly like\nin `if` branches — scoped to the branch where the test is true.\n",{"id":3576,"difficulty":105,"q":3577,"a":3578},"equals-override-example","How does instanceof pattern matching improve the equals() override?","The classic `equals()` override required an `instanceof` check followed\nby a cast. Pattern matching eliminates the cast:\n\n```java\n\u002F\u002F Old way:\n@Override\npublic boolean equals(Object o) {\n    if (!(o instanceof Point)) return false;\n    Point other = (Point) o;          \u002F\u002F redundant cast\n    return x == other.x && y == other.y;\n}\n\n\u002F\u002F With pattern matching (Java 16+):\n@Override\npublic boolean equals(Object o) {\n    return o instanceof Point other   \u002F\u002F test + bind in one step\n        && x == other.x\n        && y == other.y;\n}\n```\n\nThis is more concise and eliminates the possibility of casting to the\nwrong type by mistake.\n\n**Rule of thumb:** pattern matching `instanceof` is the idiomatic way\nto write `equals()` in Java 16+ — test and bind in a single expression.\n",{"id":3580,"difficulty":105,"q":3581,"a":3582},"pattern-matching-relationship-switch","How does instanceof pattern matching relate to switch pattern matching?","They are part of the same **pattern matching** feature family:\n\n- **`instanceof` pattern** (Java 16) — single-type check, one binding variable.\n- **Switch type pattern** (Java 21) — multi-way dispatch, one binding per case.\n\n`instanceof` is the right tool for one or two type checks; switch is better\nfor three or more:\n\n```java\n\u002F\u002F Two types — instanceof is fine:\nif (shape instanceof Circle c) {\n    return Math.PI * c.radius() * c.radius();\n} else if (shape instanceof Rectangle r) {\n    return r.w() * r.h();\n}\n\n\u002F\u002F Three or more types — switch is cleaner and exhaustive:\ndouble area = switch (shape) {\n    case Circle c        -> Math.PI * c.radius() * c.radius();\n    case Rectangle r     -> r.w() * r.h();\n    case Triangle t      -> 0.5 * t.base() * t.height();\n};\n```\n\n**Rule of thumb:** use `instanceof` patterns for one or two cases;\nswitch patterns for multi-way dispatch — especially when exhaustiveness\nchecking with sealed types is valuable.\n",{"id":3584,"difficulty":113,"q":3585,"a":3586},"no-reassignment","Can you reassign a pattern binding variable?","Pattern binding variables are **effectively final by default** but the\ncompiler does not actually enforce `final` — you can reassign them within\nthe scope. However, reassigning a pattern variable is considered bad\npractice because it breaks the clarity of the pattern-matched binding:\n\n```java\nif (obj instanceof String s) {\n    s = s.trim(); \u002F\u002F legal — but confusing: s no longer equals obj cast\n    System.out.println(s);\n}\n\n\u002F\u002F Better — use a new variable:\nif (obj instanceof String s) {\n    String trimmed = s.trim();\n    System.out.println(trimmed);\n}\n```\n\n**Rule of thumb:** treat pattern binding variables as read-only; assign\nto a new variable if you need a derived value.\n",{"id":3588,"difficulty":126,"q":3589,"a":3590},"generic-types-pattern-matching","How does instanceof pattern matching work with generic types?","Due to **type erasure**, you can only test against the **raw type**,\nnot a parameterised generic type. `obj instanceof List\u003CString>` is a\ncompile error because the generic argument is erased at runtime:\n\n```java\nObject obj = List.of(\"a\", \"b\");\n\n\u002F\u002F Compile error — generic argument not checkable at runtime:\n\u002F\u002F if (obj instanceof List\u003CString> strings) { }\n\n\u002F\u002F Use wildcard or raw type:\nif (obj instanceof List\u003C?> list) {\n    \u002F\u002F list is List\u003C?> — elements are typed as Object\n    list.forEach(System.out::println);\n}\n```\n\nIf you need to verify element types, you must check each element\nindividually inside the branch.\n\n**Rule of thumb:** test against `List\u003C?>` or the raw type with\n`instanceof`; type erasure prevents checking the generic argument.\n",{"description":103},"Java instanceof pattern matching interview questions — binding variables, scope rules, negation patterns, compound conditions, type patterns in switch, comparing old instanceof to new syntax, and practical use cases.","java\u002Fmodern-java\u002Finstanceof-pattern-matching","instanceof Pattern Matching","4HVBgAnGGLtkslxAGvvF-Xb7Oy6BMZR3ev-jCs2CDFo",{"id":3597,"title":3598,"body":3599,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":3603,"navigation":108,"order":11,"path":3604,"questions":3605,"questionsCount":980,"related":250,"seo":3665,"seoDescription":3666,"stem":3667,"subtopic":3668,"topic":28,"topicSlug":30,"updated":1068,"__hash__":3669},"qa\u002Fjava\u002Foop\u002Fequals-hashcode.md","Equals Hashcode",{"type":100,"value":3600,"toc":3601},[],{"title":103,"searchDepth":29,"depth":29,"links":3602},[],{},"\u002Fjava\u002Foop\u002Fequals-hashcode",[3606,3610,3614,3618,3622,3626,3630,3634,3638,3641,3645,3649,3653,3657,3661],{"id":3607,"difficulty":113,"q":3608,"a":3609},"equals-vs-==","What is the difference between == and equals()?","- **`==`** compares **references** for primitives' values and for objects'\n  *identity* — are these the **same object** in memory?\n- **`equals()`** compares **logical value**, as defined by the class. The\n  `Object` default is just `==`, so it means nothing useful until overridden.\n\n```java\nString a = new String(\"x\"), b = new String(\"x\");\na == b;            \u002F\u002F false — two different objects\na.equals(b);       \u002F\u002F true  — same characters\n```\n\n`==` on objects almost always indicates a bug when you meant value equality\n(the classic `String` comparison mistake). **Rule of thumb:** `==` for\nprimitives and identity; `equals()` for value.\n",{"id":3611,"difficulty":105,"q":3612,"a":3613},"object-equality-identity","What is the difference between identity, equality and equivalence?","- **Identity** — `a == b`: are they the *same object* in memory?\n- **Equality** — `a.equals(b)`: are they *logically the same value*, per the\n  class's definition?\n- Some classes also expose **ordering equivalence** via `compareTo == 0`.\n\n```java\nString a = new String(\"x\"), b = new String(\"x\");\na == b;            \u002F\u002F false (identity)\na.equals(b);       \u002F\u002F true  (equality)\n\nBigDecimal x = new BigDecimal(\"1.0\"), y = new BigDecimal(\"1.00\");\nx.equals(y);       \u002F\u002F false! (scale differs)\nx.compareTo(y) == 0; \u002F\u002F true  (numeric equivalence)\n```\n\n`BigDecimal` is the classic gotcha where `equals` and `compareTo` disagree.\n",{"id":3615,"difficulty":113,"q":3616,"a":3617},"default-equals","What does the default Object.equals() do?","The `Object` implementation compares **reference identity** — it returns `true`\nonly if both references point to the **exact same object** (`this == other`).\nSo unless you override it, two distinct objects with identical state are \"not\nequal.\"\n\n```java\nclass Point { int x, y; }\nPoint a = new Point(), b = new Point();   \u002F\u002F both (0,0)\na.equals(b);   \u002F\u002F false — default equals is identity\n```\n\nThat's why value classes (`String`, `Integer`, `LocalDate`) override `equals`.\n**Rule of thumb:** if \"two of these with the same contents should be equal,\" you\nmust override `equals` (and `hashCode`).\n",{"id":3619,"difficulty":126,"q":3620,"a":3621},"equals-hashcode","What is the equals\u002FhashCode contract?","If you override `equals`, you **must** override `hashCode`, obeying:\n\n1. Equal objects (`a.equals(b)`) **must** have equal hash codes.\n2. `equals` must be reflexive, symmetric, transitive, and consistent.\n3. Unequal objects *may* share a hash code (collisions are allowed).\n\n```java\nclass Point {\n  final int x, y;\n  @Override public boolean equals(Object o) {\n    if (this == o) return true;\n    if (!(o instanceof Point p)) return false;\n    return x == p.x && y == p.y;\n  }\n  @Override public int hashCode() { return Objects.hash(x, y); }\n}\n```\n\nBreak the contract and **hash-based collections silently misbehave**: a\n`HashMap`\u002F`HashSet` may fail to find an object whose `hashCode` doesn't match\nits `equals`. Use `Objects.hash(...)` \u002F `Objects.equals(...)` to implement them.\n",{"id":3623,"difficulty":126,"q":3624,"a":3625},"why-override-both","Why must you override hashCode whenever you override equals?","Because hash-based collections (`HashMap`, `HashSet`) **find a bucket by\n`hashCode` first**, then check `equals` within it. If two `equals` objects have\n**different** hash codes, they land in different buckets and the collection\nnever finds the match.\n\n```java\nclass Key {\n  final int id;\n  @Override public boolean equals(Object o) { \u002F* by id *\u002F return o instanceof Key k && k.id == id; }\n  \u002F\u002F no hashCode override -> uses identity hash!\n}\nvar set = new HashSet\u003CKey>();\nset.add(new Key(1));\nset.contains(new Key(1));   \u002F\u002F false! equal but different hashCode\n```\n\n**Rule of thumb:** equals and hashCode are a package deal — override neither or\nboth, derived from the **same fields**.\n",{"id":3627,"difficulty":126,"q":3628,"a":3629},"equals-properties","What properties must a correct equals() satisfy?","The `equals` contract requires five properties:\n\n- **Reflexive** — `x.equals(x)` is true.\n- **Symmetric** — `x.equals(y)` iff `y.equals(x)`.\n- **Transitive** — if `x=y` and `y=z`, then `x=z`.\n- **Consistent** — repeated calls give the same result (no random\u002Ftime inputs).\n- **Non-null** — `x.equals(null)` is false (never throws).\n\n```java\n@Override public boolean equals(Object o) {\n  if (this == o) return true;            \u002F\u002F reflexive fast-path\n  if (!(o instanceof Point p)) return false; \u002F\u002F handles null + wrong type\n  return x == p.x && y == p.y;           \u002F\u002F symmetric & transitive by construction\n}\n```\n\nSymmetry\u002Ftransitivity are the ones that break with inheritance. **Rule of\nthumb:** compare the same fields both ways and reject null\u002Fother types up front.\n",{"id":3631,"difficulty":126,"q":3632,"a":3633},"getclass-vs-instanceof","Should equals() use instanceof or getClass()?","It's a trade-off:\n\n- **`instanceof`** allows a subclass to be `equals` to its parent, but can break\n  **symmetry** if a subclass adds state.\n- **`getClass()`** requires exact same class — preserves symmetry\u002Ftransitivity\n  but means no subclass instance is ever equal to a parent instance (breaks\n  Liskov for equality).\n\n```java\n\u002F\u002F instanceof — flexible, but Sub vs Base symmetry is fragile\nif (!(o instanceof Point p)) return false;\n\u002F\u002F getClass — strict, symmetric\nif (o == null || getClass() != o.getClass()) return false;\n```\n\nEffective Java recommends `instanceof` **plus making value classes `final`** (or\nusing composition) to sidestep the subclass problem. **Rule of thumb:** prefer\n`instanceof` on a `final`\u002Frecord value type.\n",{"id":3635,"difficulty":105,"q":3636,"a":3637},"objects-helpers","How do java.util.Objects helpers simplify equals and hashCode?","`Objects` provides null-safe utilities so you don't hand-roll boilerplate:\n\n- `Objects.equals(a, b)` — null-safe equality (no NPE if `a` is null).\n- `Objects.hash(f1, f2, ...)` — combines fields into one hash code.\n- `Objects.requireNonNull(x)` — guard constructor args.\n\n```java\n@Override public boolean equals(Object o) {\n  if (this == o) return true;\n  if (!(o instanceof User u)) return false;\n  return age == u.age && Objects.equals(name, u.name); \u002F\u002F null-safe\n}\n@Override public int hashCode() { return Objects.hash(name, age); }\n```\n\n**Rule of thumb:** use `Objects.equals`\u002F`Objects.hash` for the fields — concise,\nnull-safe, and consistent with each other.\n",{"id":198,"difficulty":126,"q":3639,"a":3640},"Why is it dangerous to use a mutable object as a HashMap key?","A `HashMap` places an entry in a bucket based on the key's `hashCode` **at\ninsertion time**. If you then **mutate** a field that `hashCode`\u002F`equals` depend\non, the key's hash changes — it now hashes to a *different* bucket, and lookups\ncan no longer find it.\n\n```java\nvar map = new HashMap\u003CList\u003CInteger>, String>();\nvar key = new ArrayList\u003C>(List.of(1));\nmap.put(key, \"v\");\nkey.add(2);                 \u002F\u002F mutated — hashCode changed\nmap.get(key);               \u002F\u002F null! stranded in the old bucket\n```\n\n**Rule of thumb:** use **immutable** keys (`String`, `Integer`, records,\nenums). If a key must be mutable, never change the fields used by\n`equals`\u002F`hashCode` while it's in the map.\n",{"id":3642,"difficulty":126,"q":3643,"a":3644},"compareto-consistency","Should compareTo be consistent with equals?","It **should** be (`x.compareTo(y) == 0` iff `x.equals(y)`), and sorted\ncollections assume it. When they disagree, `TreeSet`\u002F`TreeMap` — which use\n`compareTo`, **not** `equals` — behave surprisingly.\n\n```java\nvar set = new TreeSet\u003CBigDecimal>();\nset.add(new BigDecimal(\"1.0\"));\nset.add(new BigDecimal(\"1.00\"));   \u002F\u002F compareTo == 0 -> treated as duplicate!\nset.size();                         \u002F\u002F 1, even though equals() says they differ\n```\n\n`BigDecimal` deliberately violates this (scale matters to `equals` but not\n`compareTo`). **Rule of thumb:** keep `compareTo` consistent with `equals`\nunless you have a documented reason — and know `TreeSet`\u002F`TreeMap` use ordering,\nnot equality.\n",{"id":3646,"difficulty":113,"q":3647,"a":3648},"string-equals","Why should you compare strings with equals() and not ==?","`==` compares **references**. String literals are **interned** (shared from a\npool), so `==` sometimes appears to work — but any `String` built at runtime\n(`new`, concatenation, input) is a different object, and `==` then returns\n`false` for equal text.\n\n```java\nString a = \"hi\", b = \"hi\";\na == b;              \u002F\u002F true — both the interned literal\nString c = new String(\"hi\");\na == c;              \u002F\u002F false — different object\na.equals(c);         \u002F\u002F true — same characters\n```\n\n**Rule of thumb:** always use `.equals()` (or `Objects.equals`) for string\ncontent; `==` for strings is a latent bug that \"works\" until the data comes\nfrom outside.\n",{"id":3650,"difficulty":113,"q":3651,"a":3652},"tostring","Why and how do you override toString?","The default `toString` returns `ClassName@hexHashCode` — useless in logs. Override\nit to return a readable representation, which is automatically used in string\nconcatenation, `println`, and debuggers.\n\n```java\nclass User {\n  String name; int age;\n  @Override public String toString() {\n    return \"User{name=\" + name + \", age=\" + age + \"}\";\n  }\n}\nSystem.out.println(new User()); \u002F\u002F User{name=null, age=0}\n```\n\nIt's purely for human-readable diagnostics — don't parse it programmatically.\nIDEs and `record`s can generate it for you.\n",{"id":3654,"difficulty":105,"q":3655,"a":3656},"record-equals","How do records implement equals, hashCode and toString?","A `record` **auto-generates** `equals`, `hashCode`, and `toString` from its\ncomponents — value-based equality with no boilerplate and no risk of forgetting\n`hashCode`. Two records are equal iff all their components are equal.\n\n```java\nrecord Point(int x, int y) { }\nnew Point(1, 2).equals(new Point(1, 2));   \u002F\u002F true — generated equals\nnew Point(1, 2).hashCode() == new Point(1, 2).hashCode(); \u002F\u002F true\nnew Point(1, 2).toString();                 \u002F\u002F \"Point[x=1, y=2]\"\n```\n\nYou *can* override them, but rarely should. **Rule of thumb:** for an immutable\nvalue type, a `record` is the safest way to get a correct equals\u002FhashCode —\nreach for it before hand-writing them.\n",{"id":3658,"difficulty":105,"q":3659,"a":3660},"hashcode-distribution","What makes a good hashCode implementation?","A good `hashCode`:\n\n- Is **consistent** with `equals` (equal objects -> equal hashes).\n- **Distributes** values across the `int` range so buckets fill evenly (few\n  collisions -> O(1) lookups).\n- Uses the **same fields** that `equals` uses, combined so order matters\n  (`Objects.hash` \u002F the `31 * result + field` idiom).\n\n```java\n@Override public int hashCode() {\n  return Objects.hash(name, age);   \u002F\u002F good enough for almost everything\n}\n\u002F\u002F returning a constant is *legal* but degrades HashMap to O(n)\n```\n\n**Rule of thumb:** `Objects.hash(sameFieldsAsEquals)` — never a constant, never\na field excluded from `equals`.\n",{"id":3662,"difficulty":105,"q":3663,"a":3664},"clone-vs-copy","What is wrong with Object.clone() and what is the alternative?","`clone()` is widely considered broken: it relies on the `Cloneable` marker\ninterface, bypasses constructors, does a **shallow** copy by default (shared\nmutable sub-objects), and has an awkward `protected`\u002Fchecked-exception design.\n\n```java\n\u002F\u002F Preferred: a copy constructor or static factory\nrecord Point(int x, int y) { }\nPoint copy = new Point(p.x(), p.y());          \u002F\u002F explicit, clear\n\nclass Box { Box(Box other) { \u002F* copy fields, deep where needed *\u002F } }\n```\n\n**Rule of thumb:** prefer a **copy constructor** or static factory (`copyOf`)\nover `clone()` — they're explicit, work with `final` fields, and let you control\nshallow vs deep copying.\n",{"description":103},"Java equals and hashCode interview questions — the equals\u002FhashCode contract, why you must override both, == vs equals, identity vs equality, getClass vs instanceof, Objects helpers, mutable keys, compareTo consistency and toString.","java\u002Foop\u002Fequals-hashcode","equals & hashCode","U0sQgIK0X139rE6ovsi3Q5Ukeuz4U073XMsQhd3BUW4",{"id":3671,"title":3672,"body":3673,"description":103,"difficulty":126,"extension":106,"framework":10,"frameworkSlug":8,"meta":3677,"navigation":108,"order":64,"path":3678,"questions":3679,"questionsCount":3732,"related":250,"seo":3733,"seoDescription":3734,"stem":3735,"subtopic":3672,"topic":90,"topicSlug":92,"updated":809,"__hash__":3736},"qa\u002Fjava\u002Fmodern-java\u002Fvirtual-threads.md","Virtual Threads",{"type":100,"value":3674,"toc":3675},[],{"title":103,"searchDepth":29,"depth":29,"links":3676},[],{},"\u002Fjava\u002Fmodern-java\u002Fvirtual-threads",[3680,3684,3688,3692,3696,3700,3704,3708,3712,3716,3720,3724,3728],{"id":3681,"difficulty":113,"q":3682,"a":3683},"what-are-virtual-threads","What are virtual threads in Java and what problem do they solve?","**Virtual threads** (Java 21, JEP 444, Project Loom) are lightweight\nthreads managed by the JVM rather than the OS. A traditional\n**platform thread** maps 1-to-1 to an OS thread — costly (~1 MB stack,\nslow to create, limited in number). A virtual thread is a JVM-managed\nconstruct that is **mounted onto a carrier platform thread** only when it\nneeds CPU time, and **unmounted** (parked) during blocking I\u002FO.\n\n```java\n\u002F\u002F Platform thread — one OS thread, ~1 MB stack:\nThread t = new Thread(task);\n\n\u002F\u002F Virtual thread — lightweight, ~few KB, millions possible:\nThread vt = Thread.ofVirtual().start(task);\n```\n\nThis enables a **thread-per-request** model where each HTTP request gets\nits own thread, but the JVM handles thousands of concurrent requests with\nonly a handful of OS threads underneath.\n\n**Rule of thumb:** virtual threads are not faster threads — they are\n*cheap* threads that eliminate the need to avoid blocking I\u002FO.\n",{"id":3685,"difficulty":105,"q":3686,"a":3687},"platform-vs-virtual-threads","How do virtual threads differ from platform threads?","| Aspect | Platform Thread | Virtual Thread |\n|---|---|---|\n| OS mapping | 1:1 with OS thread | Many-to-few (M:N) |\n| Stack size | ~1 MB (fixed) | ~few KB (growable) |\n| Creation cost | High (~ms) | Very low (~µs) |\n| Max concurrent | ~thousands | ~millions |\n| Blocking I\u002FO | Blocks the OS thread | JVM unmounts; carrier thread reused |\n| Thread pool needed | Yes, to limit overhead | Generally no |\n| `synchronized` | Full support | Risk of pinning (see pinning) |\n\n```java\n\u002F\u002F Platform threads need a pool to limit resource usage:\nExecutorService pool = Executors.newFixedThreadPool(200);\n\n\u002F\u002F Virtual threads: create freely per task\nExecutorService vExecutor = Executors.newVirtualThreadPerTaskExecutor();\n```\n\n**Rule of thumb:** virtual threads are the right default for I\u002FO-bound\nconcurrent tasks; platform threads remain necessary for CPU-bound work.\n",{"id":3689,"difficulty":105,"q":3690,"a":3691},"carrier-threads","What is a carrier thread and how does the JVM schedule virtual threads?","A **carrier thread** is a platform thread that a virtual thread runs on.\nThe JVM maintains a small **ForkJoinPool** of carrier threads (defaulting\nto the number of CPU cores). Virtual threads are scheduled by the JVM onto\navailable carrier threads using **cooperative scheduling**:\n\n1. Virtual thread starts executing on a carrier thread.\n2. When it hits a blocking operation (I\u002FO, `sleep`, `LockSupport.park`),\n   the JVM **unmounts** the virtual thread from the carrier — saving its\n   stack to the heap.\n3. The carrier thread is now free to run another virtual thread.\n4. When the I\u002FO completes, the virtual thread is **remounted** on any\n   available carrier thread and resumes.\n\n```\nOS threads (carrier pool): [T1] [T2] [T3] [T4]\nVirtual threads:           [V1] [V2] ... [V10000]\nV1 blocks on I\u002FO → unmounted from T1 → T1 picks up V2 immediately\n```\n\n**Rule of thumb:** the carrier pool size is set by `-Djdk.virtualThreadScheduler.parallelism=N`\n(default = CPU cores); don't increase it for I\u002FO-bound workloads.\n",{"id":3693,"difficulty":105,"q":3694,"a":3695},"thread-per-request-model","How do virtual threads enable the thread-per-request model?","Before virtual threads, thread-per-request was impractical beyond a few\nhundred concurrent requests because each request consumed an OS thread.\nFrameworks like Servlet, Spring MVC, and JDBC used **thread pools** and\n**reactive\u002Fasync** APIs to avoid blocking.\n\nWith virtual threads, the JVM handles the parking\u002Fscheduling:\n\n```java\n\u002F\u002F Spring Boot 3.2+ — enable virtual threads globally:\n\u002F\u002F spring.threads.virtual.enabled=true\n\n\u002F\u002F Or manually with Jakarta Servlets:\ntry (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n    executor.submit(() -> {\n        String data = jdbcTemplate.queryForObject(sql, String.class); \u002F\u002F blocks OK\n        return processData(data);\n    });\n}\n```\n\nEach request can use **blocking APIs** (JDBC, REST client, file I\u002FO)\nnaturally — the JVM suspends the virtual thread during the wait without\nconsuming an OS thread.\n\n**Rule of thumb:** virtual threads make simple synchronous blocking code\nscale as well as complex asynchronous reactive code — without callback\nhell or `CompletableFuture` chains.\n",{"id":3697,"difficulty":126,"q":3698,"a":3699},"pinning","What is thread pinning in virtual threads and how do you avoid it?","**Pinning** occurs when a virtual thread cannot be unmounted from its\ncarrier thread during a blocking operation. This defeats the purpose of\nvirtual threads because the carrier OS thread is held blocked.\n\nTwo situations cause pinning:\n1. **`synchronized` blocks or methods** — the JVM cannot currently\n   unmount a virtual thread that holds a monitor lock.\n2. **Native methods** — JNI frames cannot be parked.\n\n```java\nsynchronized (lock) {\n    Thread.sleep(1000); \u002F\u002F virtual thread PINNED — carrier blocked for 1 sec\n}\n\n\u002F\u002F Fix: replace synchronized with ReentrantLock:\nlock.lock();\ntry {\n    Thread.sleep(1000); \u002F\u002F virtual thread parks correctly — carrier freed\n} finally {\n    lock.unlock();\n}\n```\n\nDetect pinning with: `-Djdk.tracePinnedThreads=full` (logs whenever\npinning occurs). Java 24+ is improving `synchronized` to avoid pinning\nin most cases.\n\n**Rule of thumb:** replace `synchronized` blocks that contain blocking\ncalls with `ReentrantLock`; avoid long-running native method calls on\nvirtual threads.\n",{"id":3701,"difficulty":126,"q":3702,"a":3703},"threadlocal-virtual-threads","How does ThreadLocal behave with virtual threads and what is the alternative?","`ThreadLocal` works with virtual threads but has two problems at scale:\n\n1. If each virtual thread (potentially millions) initialises a heavy\n   `ThreadLocal` (e.g., a database connection), memory usage explodes.\n2. Thread pools reuse threads, so `ThreadLocal` values survive across\n   tasks — with virtual threads there's no pooling, so values don't leak\n   *between* tasks, but the allocation-per-thread cost remains.\n\nJava 20 introduced **Scoped Values** (`ScopedValue`, JEP 446 — finalized\nin Java 21) as the preferred alternative for virtual threads:\n\n```java\n\u002F\u002F ThreadLocal — allocated per virtual thread:\nprivate static final ThreadLocal\u003CUser> CURRENT_USER = new ThreadLocal\u003C>();\n\n\u002F\u002F ScopedValue — immutable, inherited by child threads, no per-thread alloc:\nprivate static final ScopedValue\u003CUser> CURRENT_USER = ScopedValue.newInstance();\n\nScopedValue.where(CURRENT_USER, user).run(() -> {\n    \u002F\u002F CURRENT_USER.get() returns 'user' within this scope\n    processRequest();\n});\n```\n\n`ScopedValue` is immutable and automatically cleaned up when the scope\nexits — no remove() needed, no accidental cross-task contamination.\n\n**Rule of thumb:** prefer `ScopedValue` over `ThreadLocal` for new code\non Java 21+, especially context propagation (user, trace-id, locale).\n",{"id":3705,"difficulty":126,"q":3706,"a":3707},"structured-concurrency","What is structured concurrency and how does it relate to virtual threads?","**Structured concurrency** (Java 21 preview, JEP 453) ensures that when a\ntask spawns subtasks, their lifetimes are bounded by the parent task's\nscope. If the parent fails or is cancelled, subtasks are automatically\ncancelled — no orphaned threads.\n\n```java\ntry (var scope = new StructuredTaskScope.ShutdownOnFailure()) {\n    Future\u003CString> user    = scope.fork(() -> fetchUser(id));\n    Future\u003CList\u003COrder>> orders = scope.fork(() -> fetchOrders(id));\n\n    scope.join();           \u002F\u002F wait for both\n    scope.throwIfFailed();  \u002F\u002F propagate first failure\n\n    return new Response(user.resultNow(), orders.resultNow());\n}\n\u002F\u002F Scope exits → both subtasks guaranteed to be done or cancelled\n```\n\n`ShutdownOnFailure` cancels the remaining subtasks if one fails.\n`ShutdownOnSuccess` returns as soon as any subtask succeeds (useful for\nparallel search \u002F hedging).\n\n**Rule of thumb:** structured concurrency + virtual threads = simple\nsynchronous-looking code that is safe, cancellable, and leak-free.\n",{"id":3709,"difficulty":105,"q":3710,"a":3711},"virtual-threads-not-for-cpu","When should you NOT use virtual threads?","Virtual threads are optimised for **I\u002FO-bound** work. They are not\nappropriate for:\n\n- **CPU-bound tasks** — a CPU-heavy virtual thread still occupies a\n  carrier thread for its entire run; many CPU-bound virtual threads compete\n  for the same carrier pool, starving each other. Use platform threads\n  in a `ForkJoinPool` or `newFixedThreadPool` instead.\n- **Code that relies on thread identity** — some frameworks or libraries\n  assume thread-pool reuse of `ThreadLocal`. Virtual threads don't pool,\n  so thread-identity assumptions break.\n- **Heavy synchronized sections over blocking I\u002FO** — pinning turns\n  virtual threads into expensive platform threads during those sections.\n\n```java\n\u002F\u002F Bad — CPU-bound on virtual threads starves the carrier pool:\nvar executor = Executors.newVirtualThreadPerTaskExecutor();\nexecutor.submit(() -> computePrimes(10_000_000)); \u002F\u002F blocks a carrier\n\n\u002F\u002F Better — CPU work on platform threads:\nvar pool = ForkJoinPool.commonPool();\npool.submit(() -> computePrimes(10_000_000));\n```\n\n**Rule of thumb:** virtual threads excel at I\u002FO-bound concurrent tasks;\nstick to platform thread pools for CPU-intensive computation.\n",{"id":3713,"difficulty":113,"q":3714,"a":3715},"creating-virtual-threads","What are the different ways to create virtual threads in Java?","Java 21 provides several APIs for creating virtual threads:\n\n```java\n\u002F\u002F 1. Thread.ofVirtual() builder:\nThread vt = Thread.ofVirtual()\n                  .name(\"my-virtual-thread\")\n                  .start(myTask);\n\n\u002F\u002F 2. Thread.startVirtualThread() — shorthand:\nThread vt2 = Thread.startVirtualThread(myTask);\n\n\u002F\u002F 3. ExecutorService — one virtual thread per task:\ntry (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {\n    exec.submit(task1);\n    exec.submit(task2);\n} \u002F\u002F waits for all tasks on close\n\n\u002F\u002F 4. ThreadFactory for frameworks:\nThreadFactory factory = Thread.ofVirtual().factory();\n```\n\nSpring Boot 3.2+ and Tomcat 10.1.x+ support virtual threads with a single\nproperty: `spring.threads.virtual.enabled=true`.\n\n**Rule of thumb:** for servers, use `newVirtualThreadPerTaskExecutor()`\nor the framework's built-in virtual thread support; avoid creating raw\nvirtual threads manually in application code.\n",{"id":3717,"difficulty":105,"q":3718,"a":3719},"virtual-threads-observability","How do you observe and debug virtual threads?","Standard observability tools work with virtual threads in Java 21+:\n\n```bash\n# Thread dump — shows virtual threads:\njcmd \u003Cpid> Thread.dump_to_file -format=json \u002Ftmp\u002Fthreads.json\n\n# JFR events — virtual thread mount\u002Funmount, pinning:\njava -XX:StartFlightRecording=filename=recording.jfr MyApp\n\n# Detect pinning at runtime:\njava -Djdk.tracePinnedThreads=full MyApp\n```\n\n`jstack` was updated to show virtual threads. JDK Flight Recorder (JFR)\nhas dedicated events for virtual thread lifecycle and pinning incidents.\n\nIn thread dumps, virtual threads are grouped and summarised by stack trace\nif many share the same waiting state (e.g., 50,000 threads all blocked on\nJDBC).\n\n**Rule of thumb:** enable JFR in production for virtual-thread apps;\nthe pinning events are the most important signal to watch for performance\nregressions.\n",{"id":3721,"difficulty":105,"q":3722,"a":3723},"virtual-threads-migration","How do you migrate an existing thread-pool application to virtual threads?","For most Spring\u002FJakarta EE applications, migration is a single config\nchange. For manual migration:\n\n```java\n\u002F\u002F Before — fixed platform thread pool:\nExecutorService executor = Executors.newFixedThreadPool(200);\n\n\u002F\u002F After — virtual thread per task:\nExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();\n```\n\nSteps:\n1. Replace pool creation — swap to `newVirtualThreadPerTaskExecutor()`.\n2. Remove artificial pool-size tuning (thread count limits are no longer\n   meaningful for I\u002FO-bound tasks).\n3. Audit `synchronized` blocks that contain blocking operations — replace\n   with `ReentrantLock` to avoid pinning.\n4. Replace heavy `ThreadLocal` with `ScopedValue` where context\n   propagation is needed.\n5. Run under load and check JFR for pinning events.\n\n**Rule of thumb:** the migration is usually 1–3 lines for the executor;\nthe real work is finding and fixing pinning in synchronized\u002Fnative code.\n",{"id":3725,"difficulty":126,"q":3726,"a":3727},"virtual-threads-reactive","Do virtual threads replace reactive programming (Project Reactor, RxJava)?","For most applications, virtual threads are a **simpler alternative** to\nreactive stacks for I\u002FO-bound concurrency. Instead of chaining\n`Mono`\u002F`Flux` operators or `CompletableFuture`, you write straightforward\nsynchronous blocking code that scales equally well.\n\n```java\n\u002F\u002F Reactive — non-blocking but complex:\nMono.fromCallable(() -> userRepo.findById(id))\n    .subscribeOn(Schedulers.boundedElastic())\n    .flatMap(user -> orderRepo.findByUser(user.id()))\n    .map(orders -> new Response(user, orders))\n    .subscribe(...);\n\n\u002F\u002F Virtual threads — blocking but simple:\nUser user = userRepo.findById(id);      \u002F\u002F blocks a virtual thread\nList\u003COrder> orders = orderRepo.findByUser(user.id());\nreturn new Response(user, orders);\n```\n\nReactive frameworks like Reactor and RxJava still excel at:\n- **Backpressure** — controlling producer\u002Fconsumer rates.\n- **Streaming** large data sets where you process elements as they arrive.\n- Ecosystems already built on reactive (Vert.x, Quarkus reactive).\n\n**Rule of thumb:** for new I\u002FO-bound services, prefer virtual threads +\nsynchronous code over reactive; keep reactive where backpressure or\nstreaming semantics are genuinely needed.\n",{"id":3729,"difficulty":105,"q":3730,"a":3731},"virtual-thread-identity","How can you check at runtime if a thread is a virtual thread?","Java 21 added `Thread.isVirtual()`:\n\n```java\nThread t = Thread.currentThread();\nSystem.out.println(t.isVirtual()); \u002F\u002F true if running on a virtual thread\n\n\u002F\u002F Also available as a static check:\nif (Thread.currentThread().isVirtual()) {\n    \u002F\u002F avoid synchronized blocks with blocking I\u002FO here\n}\n```\n\nVirtual threads also have distinct characteristics:\n- `isDaemon()` always returns `true`.\n- `getPriority()` is always `NORM_PRIORITY` (5) and cannot be changed.\n- They are not in any `ThreadGroup` that is meaningful to the application.\n\n**Rule of thumb:** `Thread.isVirtual()` is mainly useful in libraries\nand frameworks that need to adapt behaviour based on whether the caller\nis using virtual threads.\n",13,{"description":103},"Java virtual threads interview questions — Project Loom, platform vs virtual threads, carrier threads, structured concurrency, thread-per-request model, pinning, ThreadLocal, when to use virtual threads, and migration from thread pools.","java\u002Fmodern-java\u002Fvirtual-threads","CJ5_11SmZBZ-4Y7VslMrt2_RJxor76bAmXrfb5bqjk4",{"id":3738,"title":3739,"body":3740,"description":103,"difficulty":105,"extension":106,"framework":10,"frameworkSlug":8,"meta":3744,"navigation":108,"order":73,"path":3745,"questions":3746,"questionsCount":3791,"related":250,"seo":3792,"seoDescription":3793,"stem":3794,"subtopic":3739,"topic":90,"topicSlug":92,"updated":809,"__hash__":3795},"qa\u002Fjava\u002Fmodern-java\u002Frecord-patterns.md","Record Patterns",{"type":100,"value":3741,"toc":3742},[],{"title":103,"searchDepth":29,"depth":29,"links":3743},[],{},"\u002Fjava\u002Fmodern-java\u002Frecord-patterns",[3747,3751,3755,3759,3763,3767,3771,3775,3779,3783,3787],{"id":3748,"difficulty":113,"q":3749,"a":3750},"what-are-record-patterns","What are record patterns in Java?","**Record patterns** (Java 21, JEP 440) extend pattern matching to\n**destructure** record components directly in an `instanceof` or `switch`\nexpression, binding each component to a local variable in one step.\n\n```java\nrecord Point(int x, int y) {}\n\nObject obj = new Point(3, 4);\n\n\u002F\u002F Old way — instanceof check, then accessor calls:\nif (obj instanceof Point p) {\n    int x = p.x();\n    int y = p.y();\n    System.out.println(x + \", \" + y);\n}\n\n\u002F\u002F Record pattern — destructure inline:\nif (obj instanceof Point(int x, int y)) {\n    System.out.println(x + \", \" + y); \u002F\u002F x and y bound directly\n}\n```\n\n**Rule of thumb:** use record patterns when you need multiple components\nof a record — they eliminate the accessor boilerplate.\n",{"id":3752,"difficulty":113,"q":3753,"a":3754},"record-patterns-in-switch","How do record patterns work in switch expressions?","Record patterns integrate seamlessly into switch type patterns, making\nmulti-branch dispatch over record-carrying sealed types concise:\n\n```java\nsealed interface Shape permits Circle, Rectangle {}\nrecord Circle(double radius)        implements Shape {}\nrecord Rectangle(double w, double h) implements Shape {}\n\ndouble area(Shape s) {\n    return switch (s) {\n        case Circle(double r)            -> Math.PI * r * r;\n        case Rectangle(double w, double h) -> w * h;\n    };\n}\n```\n\nThe components `r`, `w`, `h` are bound directly in each case — no\naccessor calls, no intermediate variables.\n\n**Rule of thumb:** record patterns in switch are the natural companion\nto sealed interfaces — together they model exhaustive dispatch over\ntyped data cleanly.\n",{"id":3756,"difficulty":105,"q":3757,"a":3758},"nested-record-patterns","What are nested record patterns and when are they useful?","Record pattern components can themselves be patterns — you can destructure\na component that is another record, arbitrarily deep:\n\n```java\nrecord Point(int x, int y) {}\nrecord Line(Point start, Point end) {}\n\nObject obj = new Line(new Point(0, 0), new Point(3, 4));\n\nif (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {\n    double length = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));\n    System.out.println(\"Length: \" + length); \u002F\u002F 5.0\n}\n```\n\nNested patterns are especially powerful for recursive data structures like\nexpression trees, JSON documents, or domain events.\n\n**Rule of thumb:** nested patterns eliminate deep chains of accessor calls\non nested records — write the shape of the data you expect, bind the values.\n",{"id":3760,"difficulty":113,"q":3761,"a":3762},"var-in-record-patterns","Can you use var in a record pattern?","Yes. `var` infers the component type, which is useful when the type is\nlong or obvious from context:\n\n```java\nrecord Pair\u003CA, B>(A first, B second) {}\n\nObject obj = new Pair\u003C>(\"hello\", 42);\n\nif (obj instanceof Pair(var first, var second)) {\n    System.out.println(first + \" \" + second); \u002F\u002F \"hello 42\"\n    \u002F\u002F first is String, second is Integer — inferred\n}\n```\n\n`var` in a record pattern behaves the same as `var` in a local variable\ndeclaration — the type is fixed at compile time, just written shorter.\n\n**Rule of thumb:** use `var` in record patterns when the component types\nare verbose (e.g., `Map.Entry\u003CString, List\u003CInteger>>`) or clearly\napparent from context.\n",{"id":3764,"difficulty":126,"q":3765,"a":3766},"record-patterns-with-generics","How do generic records work with record patterns?","Record patterns support generic records, but due to **type erasure** the\ncomponent types must be compatible with the inferred erasure. Using\nexplicit types works; using concrete parameterisations may require a\ncast or `var`:\n\n```java\nrecord Box\u003CT>(T value) {}\n\nObject obj = new Box\u003C>(\"hello\");\n\n\u002F\u002F Using var — inferred as Object due to erasure:\nif (obj instanceof Box(var v)) {\n    System.out.println(v); \u002F\u002F \"hello\" — but v is typed as Object\n}\n\n\u002F\u002F Explicit type — works if you know the component type:\nif (obj instanceof Box(String s)) {\n    System.out.println(s.toUpperCase()); \u002F\u002F s is String — unchecked\n}\n```\n\nThe compiler may emit an unchecked warning for the explicit-type case\nbecause the generic argument is not verifiable at runtime (erasure).\n\n**Rule of thumb:** use `var` for generic record patterns to avoid\nunchecked warnings; add an explicit type only when you're certain of\nthe component's runtime type.\n",{"id":3768,"difficulty":105,"q":3769,"a":3770},"guarded-record-patterns","Can you add a when guard to a record pattern in switch?","Yes. `when` guards work with record patterns just like with type patterns:\n\n```java\nsealed interface Expr permits Num, Add {}\nrecord Num(int v)           implements Expr {}\nrecord Add(Expr l, Expr r)  implements Expr {}\n\nString describe(Expr e) {\n    return switch (e) {\n        case Num(int v) when v \u003C 0   -> \"negative: \" + v;\n        case Num(int v) when v == 0  -> \"zero\";\n        case Num(int v)              -> \"positive: \" + v;\n        case Add(Expr l, Expr r)     -> \"sum of \" + describe(l) + \" and \" + describe(r);\n    };\n}\n```\n\n**Rule of thumb:** combine `when` with record patterns to filter on\ncomponent values without a nested `if` inside the case body.\n",{"id":3772,"difficulty":105,"q":3773,"a":3774},"record-patterns-replace-visitor","How do record patterns help replace the Visitor pattern?","The Visitor pattern was a workaround for Java's lack of multi-dispatch and\nsealed type exhaustiveness. Record patterns + sealed interfaces + switch\nreplace it with far less ceremony:\n\n```java\n\u002F\u002F Visitor pattern — 30+ lines, double dispatch, accept\u002Fvisit boilerplate:\ninterface ExprVisitor\u003CR> {\n    R visitNum(Num n);\n    R visitAdd(Add a);\n}\n\u002F\u002F Each record implements accept(ExprVisitor\u003CR>)...\n\n\u002F\u002F Record patterns — same result, no infrastructure:\nsealed interface Expr permits Num, Add {}\nrecord Num(int v)           implements Expr {}\nrecord Add(Expr l, Expr r)  implements Expr {}\n\nint eval(Expr e) {\n    return switch (e) {\n        case Num(int v)           -> v;\n        case Add(Expr l, Expr r)  -> eval(l) + eval(r);\n    };\n}\n\nString print(Expr e) {\n    return switch (e) {\n        case Num(int v)           -> String.valueOf(v);\n        case Add(Expr l, Expr r)  -> \"(\" + print(l) + \" + \" + print(r) + \")\";\n    };\n}\n```\n\nAdding a new operation (`eval`, `print`, `typecheck`) requires writing one\nnew function — no changes to existing classes, no new visitor interfaces.\n\n**Rule of thumb:** sealed + records + switch patterns = Visitor pattern\nwithout the boilerplate. Adding a new type forces you to update every switch\n(compile error); adding a new operation requires only a new function.\n",{"id":3776,"difficulty":105,"q":3777,"a":3778},"record-patterns-instanceof-scope","What is the scope of variables bound in a record pattern instanceof?","Variables bound in a record pattern `instanceof` follow the same\nflow-sensitive scoping rules as simple type patterns — they are in scope\nonly in the branch where the match is guaranteed:\n\n```java\nrecord Point(int x, int y) {}\n\nObject obj = new Point(1, 2);\n\nif (obj instanceof Point(int x, int y)) {\n    System.out.println(x + \", \" + y); \u002F\u002F in scope here\n}\n\u002F\u002F x and y are NOT in scope here\n\n\u002F\u002F Also works with && guards:\nif (obj instanceof Point(int x, int y) && x > 0 && y > 0) {\n    System.out.println(\"first quadrant: \" + x + \", \" + y);\n}\n```\n\n**Rule of thumb:** record pattern variables behave exactly like simple\npattern variables — scoped to the true branch and `&&` chains.\n",{"id":3780,"difficulty":113,"q":3781,"a":3782},"record-patterns-null","What happens when a record pattern is matched against null?","Like all `instanceof` patterns, a record pattern **does not match null** —\n`instanceof` returns `false` for null regardless of the pattern:\n\n```java\nrecord Point(int x, int y) {}\nObject obj = null;\n\nSystem.out.println(obj instanceof Point(int x, int y)); \u002F\u002F false\n\u002F\u002F x and y are never bound; no NPE\n\n\u002F\u002F In switch, null must be handled explicitly:\nswitch (obj) {\n    case null             -> System.out.println(\"null\");\n    case Point(int x, int y) -> System.out.println(x + \",\" + y);\n    default               -> System.out.println(\"other\");\n}\n```\n\n**Rule of thumb:** null never matches a record pattern — handle it with\n`case null` in switch or an explicit null check before `instanceof`.\n",{"id":3784,"difficulty":105,"q":3785,"a":3786},"record-patterns-exhaustive","How do record patterns interact with exhaustiveness checking in switch?","Exhaustiveness checking applies to the **outer** type pattern, not to the\ninternal component structure. When the selector is a sealed type, the\ncompiler checks that all permitted subtypes are covered:\n\n```java\nsealed interface Shape permits Circle, Rect {}\nrecord Circle(double r)     implements Shape {}\nrecord Rect(double w, double h) implements Shape {}\n\n\u002F\u002F Exhaustive — all subtypes covered:\ndouble area(Shape s) {\n    return switch (s) {\n        case Circle(double r)          -> Math.PI * r * r;\n        case Rect(double w, double h)  -> w * h;\n    };\n}\n\u002F\u002F Adding a new Shape subtype → compile error here\n```\n\nThe compiler does not (currently) check exhaustiveness of component\nvalues — that's the role of `when` guards plus a `default` or catch-all.\n\n**Rule of thumb:** exhaustiveness in switch refers to which subtypes are\ncovered, not which component values — add `when` guards for component-level\nconditions and a final ungarded case as the catch-all.\n",{"id":3788,"difficulty":113,"q":3789,"a":3790},"record-patterns-vs-accessor-chain","When should you use a record pattern versus calling accessors?","Use a **record pattern** when you need most or all components of a record:\n\n```java\n\u002F\u002F If you need both x and y — record pattern is cleaner:\nif (obj instanceof Point(int x, int y)) {\n    System.out.println(x + \", \" + y);\n}\n\n\u002F\u002F If you need only one component — accessor is simpler:\nif (obj instanceof Point p) {\n    System.out.println(p.x()); \u002F\u002F only x needed\n}\n```\n\nFor nested records where you'd need multiple accessor calls, the pattern\nis significantly more readable:\n\n```java\n\u002F\u002F Accessor chain — verbose:\nif (obj instanceof Line l) {\n    int x1 = l.start().x();\n    int y1 = l.start().y();\n    int x2 = l.end().x();\n    int y2 = l.end().y();\n    ...\n}\n\n\u002F\u002F Nested record pattern — concise:\nif (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {\n    ...\n}\n```\n\n**Rule of thumb:** record patterns pay off when you need multiple\ncomponents or when nesting is deep; stick to accessors for single-field\naccess.\n",11,{"description":103},"Java record patterns interview questions — deconstruction patterns, nested patterns, record patterns in instanceof, record patterns in switch, combining with sealed classes, var in patterns, and replacing instanceof chains.","java\u002Fmodern-java\u002Frecord-patterns","LY-WRR4LYHVxfjMQETGKTfLJWYOmwFd-4645hikOe2A",{"id":3797,"title":3798,"body":3799,"description":103,"difficulty":113,"extension":106,"framework":10,"frameworkSlug":8,"meta":3803,"navigation":108,"order":82,"path":3804,"questions":3805,"questionsCount":3791,"related":250,"seo":3850,"seoDescription":3851,"stem":3852,"subtopic":3798,"topic":90,"topicSlug":92,"updated":809,"__hash__":3853},"qa\u002Fjava\u002Fmodern-java\u002Fsequenced-collections.md","Sequenced Collections",{"type":100,"value":3800,"toc":3801},[],{"title":103,"searchDepth":29,"depth":29,"links":3802},[],{},"\u002Fjava\u002Fmodern-java\u002Fsequenced-collections",[3806,3810,3814,3818,3822,3826,3830,3834,3838,3842,3846],{"id":3807,"difficulty":113,"q":3808,"a":3809},"what-are-sequenced-collections","What are sequenced collections and why were they added in Java 21?","**Sequenced collections** (Java 21, JEP 431) introduce three new\ninterfaces — `SequencedCollection`, `SequencedSet`, and `SequencedMap` —\nthat give a **uniform API for accessing the first and last elements** and\nfor **iterating in reverse order** across all ordered collection types.\n\nBefore Java 21 each collection had its own non-uniform way to get the\nfirst or last element:\n\n```java\nList\u003CString> list = List.of(\"a\", \"b\", \"c\");\nlist.get(0);                           \u002F\u002F first element\nlist.get(list.size() - 1);             \u002F\u002F last element — verbose\n\nDeque\u003CString> deque = new ArrayDeque\u003C>(list);\ndeque.peekFirst();                     \u002F\u002F first\ndeque.peekLast();                      \u002F\u002F last\n\nSortedSet\u003CString> sorted = new TreeSet\u003C>(list);\nsorted.first();                        \u002F\u002F first\nsorted.last();                         \u002F\u002F last\n```\n\n`SequencedCollection` unifies these with `getFirst()` \u002F `getLast()`.\n\n**Rule of thumb:** if you need the first or last element, check whether\nthe collection is a `SequencedCollection` and use the new API.\n",{"id":3811,"difficulty":113,"q":3812,"a":3813},"sequenced-collection-interface","What methods does SequencedCollection add?","`SequencedCollection\u003CE>` extends `Collection\u003CE>` and adds:\n\n| Method | Description |\n|---|---|\n| `getFirst()` | Returns the first element; throws `NoSuchElementException` if empty |\n| `getLast()` | Returns the last element; throws `NoSuchElementException` if empty |\n| `addFirst(E)` | Inserts at the beginning (optional — throws `UnsupportedOperationException` for fixed-size) |\n| `addLast(E)` | Inserts at the end (optional) |\n| `removeFirst()` | Removes and returns the first element (optional) |\n| `removeLast()` | Removes and returns the last element (optional) |\n| `reversed()` | Returns a reversed view of the collection |\n\n```java\nList\u003CString> list = new ArrayList\u003C>(List.of(\"a\", \"b\", \"c\"));\n\nSystem.out.println(list.getFirst()); \u002F\u002F \"a\"\nSystem.out.println(list.getLast());  \u002F\u002F \"c\"\n\nlist.addFirst(\"z\");                  \u002F\u002F [\"z\", \"a\", \"b\", \"c\"]\nlist.addLast(\"x\");                   \u002F\u002F [\"z\", \"a\", \"b\", \"c\", \"x\"]\n\nlist.removeFirst();                  \u002F\u002F \"z\" removed\nlist.removeLast();                   \u002F\u002F \"x\" removed\n```\n\n**Rule of thumb:** `getFirst()`\u002F`getLast()` replace `get(0)` and\n`get(list.size()-1)` — use them for cleaner, more readable code.\n",{"id":3815,"difficulty":113,"q":3816,"a":3817},"sequenced-set-interface","What is SequencedSet and which classes implement it?","`SequencedSet\u003CE>` extends both `SequencedCollection\u003CE>` and `Set\u003CE>`,\nadding no new methods but guaranteeing both the set contract (no\nduplicates) and a defined encounter order.\n\nImplementing classes:\n- `LinkedHashSet` — insertion-ordered set, implements `SequencedSet`\n- `SortedSet` subtypes: `TreeSet` — sorted, implements `SequencedSet`\n  via `SortedSet` (which extends `SequencedSet`)\n\n```java\nSequencedSet\u003CString> set = new LinkedHashSet\u003C>(List.of(\"b\", \"a\", \"c\"));\nSystem.out.println(set.getFirst()); \u002F\u002F \"b\" — insertion order\nSystem.out.println(set.getLast());  \u002F\u002F \"c\"\nSystem.out.println(set.reversed()); \u002F\u002F [\"c\", \"a\", \"b\"] — reversed view\n```\n\n**Rule of thumb:** `SequencedSet` lets you treat `LinkedHashSet` and\n`TreeSet` uniformly when you need first\u002Flast\u002Freversed without knowing\nthe concrete type.\n",{"id":3819,"difficulty":105,"q":3820,"a":3821},"sequenced-map-interface","What is SequencedMap and what methods does it add?","`SequencedMap\u003CK,V>` extends `Map\u003CK,V>` and adds methods to access\nthe first and last entries:\n\n| Method | Description |\n|---|---|\n| `firstEntry()` | Returns (but does not remove) the first `Map.Entry` |\n| `lastEntry()` | Returns the last `Map.Entry` |\n| `pollFirstEntry()` | Removes and returns the first entry |\n| `pollLastEntry()` | Removes and returns the last entry |\n| `putFirst(K, V)` | Inserts\u002Fmoves entry to the front (optional) |\n| `putLast(K, V)` | Inserts\u002Fmoves entry to the back (optional) |\n| `reversed()` | Returns a reversed-order map view |\n| `sequencedKeySet()` | Returns a `SequencedSet\u003CK>` |\n| `sequencedValues()` | Returns a `SequencedCollection\u003CV>` |\n| `sequencedEntrySet()` | Returns a `SequencedSet\u003CMap.Entry\u003CK,V>>` |\n\n```java\nSequencedMap\u003CString, Integer> map = new LinkedHashMap\u003C>();\nmap.put(\"a\", 1); map.put(\"b\", 2); map.put(\"c\", 3);\n\nSystem.out.println(map.firstEntry()); \u002F\u002F a=1\nSystem.out.println(map.lastEntry());  \u002F\u002F c=3\n\nmap.putFirst(\"z\", 0);                \u002F\u002F {z=0, a=1, b=2, c=3}\n```\n\n**Rule of thumb:** `SequencedMap` lets you use `LinkedHashMap` and\n`TreeMap` with a uniform first\u002Flast\u002Freversed API without casting.\n",{"id":3823,"difficulty":113,"q":3824,"a":3825},"which-collections-implement","Which existing Java collections implement the new sequenced interfaces?","The new interfaces are retrofitted onto the existing type hierarchy:\n\n| Collection | Implements |\n|---|---|\n| `ArrayList`, `LinkedList`, `ArrayDeque` | `SequencedCollection` |\n| `LinkedHashSet` | `SequencedSet` |\n| `TreeSet` | `SequencedSet` (via `SortedSet`) |\n| `LinkedHashMap` | `SequencedMap` |\n| `TreeMap` | `SequencedMap` (via `SortedMap`) |\n| `List` (interface) | `SequencedCollection` |\n| `Deque` (interface) | `SequencedCollection` |\n| `SortedSet` (interface) | `SequencedSet` |\n| `SortedMap` (interface) | `SequencedMap` |\n\n```java\nSequencedCollection\u003CInteger> col = new ArrayDeque\u003C>(List.of(1, 2, 3));\ncol.getFirst(); \u002F\u002F 1\ncol.getLast();  \u002F\u002F 3\n```\n\n**Rule of thumb:** if the concrete type is `ArrayList`, `LinkedHashSet`,\n`TreeMap`, etc. you already have the new methods — no migration needed.\n",{"id":3827,"difficulty":105,"q":3828,"a":3829},"reversed-method","What does the reversed() method return?","`reversed()` returns a **live, write-through view** of the collection in\nreverse encounter order. Mutations through the reversed view are reflected\nin the original, and vice versa.\n\n```java\nList\u003CString> list = new ArrayList\u003C>(List.of(\"a\", \"b\", \"c\"));\nList\u003CString> rev  = list.reversed();\n\nSystem.out.println(rev);   \u002F\u002F [c, b, a]\n\nrev.addFirst(\"z\");         \u002F\u002F adds to the reversed view's front\nSystem.out.println(list);  \u002F\u002F [a, b, c, z]  — \"z\" is at the END of original\n\nlist.add(\"x\");             \u002F\u002F adds to original\nSystem.out.println(rev);   \u002F\u002F [x, z, c, b, a] — reflected in reversed view\n```\n\n**Rule of thumb:** `reversed()` is a live view, not a copy — mutations\npropagate both ways; if you need an independent copy, copy it explicitly.\n",{"id":3831,"difficulty":113,"q":3832,"a":3833},"list-getfirst-vs-get0","Is list.getFirst() just a synonym for list.get(0)?","For `List` implementations, `getFirst()` is equivalent to `get(0)` except\nfor the exception when the list is empty. `get(0)` throws\n`IndexOutOfBoundsException`; `getFirst()` throws `NoSuchElementException`.\n\n```java\nList\u003CString> empty = new ArrayList\u003C>();\n\nempty.get(0);      \u002F\u002F IndexOutOfBoundsException: Index 0 out of bounds\nempty.getFirst();  \u002F\u002F NoSuchElementException\n\nList\u003CString> list = List.of(\"a\", \"b\", \"c\");\nlist.get(0);       \u002F\u002F \"a\"\nlist.getFirst();   \u002F\u002F \"a\" — same result\n```\n\nThe semantic difference: `IndexOutOfBoundsException` signals a programming\nerror (index miscalculation); `NoSuchElementException` signals an empty\ncollection. `getFirst()` better expresses intent.\n\n**Rule of thumb:** prefer `getFirst()` \u002F `getLast()` over `get(0)` and\n`get(size-1)` — the intent is clearer and the exception type is more\nsemantically correct.\n",{"id":3835,"difficulty":105,"q":3836,"a":3837},"sequenced-vs-deque","How does SequencedCollection relate to Deque?","`Deque` already had `peekFirst()`\u002F`peekLast()`, `pollFirst()`\u002F`pollLast()`,\n`addFirst()`\u002F`addLast()`. The new `SequencedCollection` essentially makes\nthese methods available on all ordered collections uniformly:\n\n| Deque method | SequencedCollection equivalent |\n|---|---|\n| `peekFirst()` | `getFirst()` |\n| `peekLast()` | `getLast()` |\n| `pollFirst()` | `removeFirst()` |\n| `pollLast()` | `removeLast()` |\n| `addFirst(e)` | `addFirst(e)` |\n| `addLast(e)` | `addLast(e)` |\n\nDeque itself now extends `SequencedCollection`, so `ArrayDeque` and\n`LinkedList` implement both and can be used interchangeably with either API.\n\n**Rule of thumb:** `Deque` and `SequencedCollection` now share the first\u002F\nlast API — prefer `SequencedCollection` in method signatures when you don't\nneed `Deque`-specific operations like `push()`\u002F`pop()`.\n",{"id":3839,"difficulty":105,"q":3840,"a":3841},"unmodifiable-sequenced","Do Collections.unmodifiableList() and List.of() support SequencedCollection?","Yes. `List` now extends `SequencedCollection`, so all `List` instances —\nincluding `List.of()` (immutable), `Collections.unmodifiableList()`, and\n`Arrays.asList()` — have `getFirst()`\u002F`getLast()`:\n\n```java\nList\u003CString> immutable = List.of(\"a\", \"b\", \"c\");\nSystem.out.println(immutable.getFirst()); \u002F\u002F \"a\" — works fine\nSystem.out.println(immutable.getLast());  \u002F\u002F \"c\"\n\n\u002F\u002F Mutation methods throw UnsupportedOperationException on immutable lists:\nimmutable.addFirst(\"z\"); \u002F\u002F UnsupportedOperationException\n```\n\n**Rule of thumb:** `getFirst()`\u002F`getLast()` are safe on any `List`,\nincluding immutable ones; mutation methods follow the same modifiability\nrules as before.\n",{"id":3843,"difficulty":113,"q":3844,"a":3845},"before-java21-workarounds","What were the workarounds for getting first\u002Flast elements before Java 21?","Each collection type needed a different API:\n\n```java\n\u002F\u002F List — verbose index arithmetic:\nString first = list.get(0);\nString last  = list.get(list.size() - 1);\n\n\u002F\u002F LinkedList (as Deque) — dedicated methods:\nString first = ((LinkedList\u003CString>) list).getFirst();\n\n\u002F\u002F ArrayDeque:\nString first = deque.peekFirst();\nString last  = deque.peekLast();\n\n\u002F\u002F SortedSet \u002F TreeSet:\nString first = sortedSet.first();\nString last  = sortedSet.last();\n\n\u002F\u002F Iterating in reverse — no unified API:\nCollections.reverse(list); \u002F\u002F mutates the list!\n\u002F\u002F Or:\nListIterator\u003CString> it = list.listIterator(list.size());\nwhile (it.hasPrevious()) System.out.println(it.previous());\n```\n\n`SequencedCollection` replaces all of these with `getFirst()`, `getLast()`,\nand `reversed()`.\n\n**Rule of thumb:** if you wrote `list.get(list.size()-1)` before Java 21,\nreplace it with `list.getLast()` — it is shorter and communicates intent.\n",{"id":3847,"difficulty":105,"q":3848,"a":3849},"sequenced-in-method-signatures","When should you use SequencedCollection as a method parameter type?","Use `SequencedCollection\u003CE>` (or `SequencedMap\u003CK,V>`) in method signatures\nwhen your method **specifically needs first\u002Flast access or reverse\niteration** but doesn't need to know the concrete type:\n\n```java\n\u002F\u002F Accept any ordered collection with first\u002Flast semantics:\nstatic \u003CT> T middle(SequencedCollection\u003CT> col) {\n    \u002F\u002F Use getFirst\u002FgetLast without caring if it's ArrayList or LinkedHashSet\n    if (col.isEmpty()) throw new NoSuchElementException();\n    \u002F\u002F ... navigate to middle via iterator\n}\n\n\u002F\u002F Too narrow — only works for List:\nstatic \u003CT> T middle(List\u003CT> list) { ... }\n\n\u002F\u002F Too broad — Collection doesn't guarantee order:\nstatic \u003CT> T middle(Collection\u003CT> col) { ... } \u002F\u002F getFirst() doesn't exist\n```\n\n**Rule of thumb:** prefer `SequencedCollection` over `List` in signatures\nwhen order and first\u002Flast access matter but random index access (`get(i)`)\ndoes not.\n",{"description":103},"Java sequenced collections interview questions — SequencedCollection, SequencedSet, SequencedMap, getFirst\u002FgetLast, addFirst\u002FaddLast, reversed(), which collections implement the new interfaces, and migration from workarounds.","java\u002Fmodern-java\u002Fsequenced-collections","Aswq8TvLa3y5unPRdSW-X5Ypb8giKFStzLf2q6t9AmY",1782244096778]