[{"data":1,"prerenderedAt":115},["ShallowReactive",2],{"qa-\u002Fjava\u002Fmodern-java\u002Finstanceof-pattern-matching":3},{"page":4,"siblings":83,"blog":112},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":73,"related":74,"seo":75,"seoDescription":76,"stem":77,"subtopic":78,"topic":79,"topicSlug":80,"updated":81,"__hash__":82},"qa\u002Fjava\u002Fmodern-java\u002Finstanceof-pattern-matching.md","Instanceof Pattern Matching",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"easy","md","Java","java",{},true,5,"\u002Fjava\u002Fmodern-java\u002Finstanceof-pattern-matching",[23,27,32,36,40,44,48,52,56,60,64,68],{"id":24,"difficulty":14,"q":25,"a":26},"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":28,"difficulty":29,"q":30,"a":31},"binding-variable-scope","medium","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":33,"difficulty":29,"q":34,"a":35},"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":37,"difficulty":29,"q":38,"a":39},"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":41,"difficulty":14,"q":42,"a":43},"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":45,"difficulty":29,"q":46,"a":47},"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":49,"difficulty":14,"q":50,"a":51},"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":53,"difficulty":29,"q":54,"a":55},"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":57,"difficulty":29,"q":58,"a":59},"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":61,"difficulty":29,"q":62,"a":63},"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":65,"difficulty":14,"q":66,"a":67},"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":69,"difficulty":70,"q":71,"a":72},"generic-types-pattern-matching","hard","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",12,null,{"description":11},"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","Modern Java","modern-java","2026-06-20","4HVBgAnGGLtkslxAGvvF-Xb7Oy6BMZR3ev-jCs2CDFo",[84,88,91,95,99,100,104,108],{"subtopic":85,"path":86,"order":87},"Records","\u002Fjava\u002Fmodern-java\u002Frecords",1,{"subtopic":89,"path":90,"order":12},"Sealed Classes","\u002Fjava\u002Fmodern-java\u002Fsealed-classes",{"subtopic":92,"path":93,"order":94},"Switch Pattern Matching","\u002Fjava\u002Fmodern-java\u002Fswitch-pattern-matching",3,{"subtopic":96,"path":97,"order":98},"Text Blocks","\u002Fjava\u002Fmodern-java\u002Ftext-blocks",4,{"subtopic":78,"path":21,"order":20},{"subtopic":101,"path":102,"order":103},"Virtual Threads","\u002Fjava\u002Fmodern-java\u002Fvirtual-threads",6,{"subtopic":105,"path":106,"order":107},"Record Patterns","\u002Fjava\u002Fmodern-java\u002Frecord-patterns",7,{"subtopic":109,"path":110,"order":111},"Sequenced Collections","\u002Fjava\u002Fmodern-java\u002Fsequenced-collections",8,{"path":113,"title":114},"\u002Fblog\u002Fjava-instanceof-pattern-matching","Java instanceof Pattern Matching — Type Tests Without the Redundant Cast",1782244117640]