How do nested record patterns work, and how can 'var' be used inside a record pattern?
answer
- Patterns are recursive: a pattern can sit where a sub-pattern goes
- Line(Point(var x1,var y1), Point(var x2,var y2)) binds all four
- Matching is outside-in; any failed level fails the whole pattern
- var infers the component's declared type, adds no extra test
- Still need a sub-pattern per component at every level
basics
~20 sIf a record's component is itself a record, you can write a pattern inside a pattern to reach deep values in one line, like 'Line(Point(var x1, var y1), Point(var x2, var y2))'. Using 'var' lets the compiler infer each component's type so you don't repeat it.
solid answer
~50 sA nested record pattern places a record pattern where a sub-pattern would go, letting you deconstruct a record whose components are themselves records. For example, with 'record Line(Point start, Point end)' you can match 'line instanceof Line(Point(var x1, var y1), Point(var x2, var y2))' and bind all four coordinates at once, without intermediate variables or accessor chains. The matching is recursive: the outer type is tested, then each inner pattern is applied to the corresponding component. 'var' is a sub-pattern that binds the component but lets the compiler infer its static type, so 'Point(var x, var y)' is equivalent to 'Point(int x, int y)' here while staying concise and refactor-friendly. A nested pattern over a reference-typed component adds a runtime type test for that level; if that inner type doesn't match, the whole pattern fails to match.
code
java · 9 linesrecord Point(int x, int y) {}
record Line(Point start, Point end) {}
static String describe(Object obj) {
if (obj instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
return "Line from (" + x1 + "," + y1 + ") to (" + x2 + "," + y2 + ")";
}
return "not a line";
}go deeper
Recognizes that you can write a pattern inside a pattern to reach nested record fields, and that var means 'infer the type'.
Explains recursive outside-in matching, that every component needs a sub-pattern at each level, and that var binds without an added type test.
Discusses failure semantics (any level fails => whole pattern fails, no bindings), null behavior on nested reference components, and when var aids refactoring vs explicit types for readability.
Frames nested patterns as structural matching for algebraic data, weighs readability/maintainability trade-offs of deep nesting, and connects to sealed-hierarchy exhaustiveness in switch.
## Recursive structure of patterns A record pattern's sub-patterns are themselves patterns. Since a record pattern *is* a pattern, you can put one inside another — that is **nesting**. This makes patterns recursive: they describe the shape of arbitrarily deep data. Setup: ```java record Point(int x, int y) {} record Line(Point start, Point end) {} ``` A `Line`'s components are `Point` values. To reach the coordinates without nesting you would deconstruct one level, then call accessors: ```java if (obj instanceof Line(Point start, Point end)) { int x1 = start.x(), y1 = start.y(); int x2 = end.x(), y2 = end.y(); } ``` With **nested record patterns** you express the full shape in one place: ```java if (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) { // x1, y1, x2, y2 all bound } ``` ## How nested matching evaluates Matching proceeds outside-in and component-by-component: 1. Is `obj` a `Line`? If not, no match. 2. Take its `start` component. Apply the sub-pattern `Point(int x1, int y1)` to it: is it a `Point`? Bind `x1`, `y1`. 3. Take its `end` component and apply `Point(int x2, int y2)` similarly. If any level fails its type test, the **entire** pattern fails and none of the variables are in scope. Each nested record pattern over a reference type contributes its own runtime `instanceof`-style check. ## The `var` sub-pattern `var` used as a sub-pattern (a **var pattern**) binds the component but lets the compiler **infer** its static type from the record's declared component type. So `Point(var x, var y)` infers `x` and `y` as `int`, identical in behavior to `Point(int x, int y)` here. Benefits: - **Concise** for deeply nested or generic shapes where spelling every type is noisy. - **Refactor-safe**: if a component's type changes, `var` follows it without edits. - A var pattern **always matches** the component's type (it imposes no additional type test), it only binds — useful when you don't want to narrow. You can mix `var`/explicit across different components (e.g. `Mapping(String key, var value)`) freely. ## Why nesting matters Nested patterns turn multi-step destructuring into a single declarative shape that the compiler validates against the actual record definitions. Combined with `switch`, they let you branch on the *structure* of data, which is the heart of data-oriented programming in modern Java. ## Caveats - You still must supply a sub-pattern for **every** component at each level; you cannot skip one. Use `var` for components you don't need. - Nesting only applies where the component is itself a record (or a reference type you further type-pattern). A primitive component takes a simple `int x`/`var x` sub-pattern. - A nested pattern over a reference component does not match `null` for that component in `instanceof`/`switch` (the inner type test rejects null), so a `Line` whose `start` is null would not match `Line(Point(...), ...)`.
- Is 'Point(var x, var y)' different from 'Point(int x, int y)' for this record?Behaviorally no — var infers int from the component declarations, so both bind the same int variables. var is just terser and survives a component-type change without editing the pattern.
- What happens to the bound variables if the inner Point pattern fails to match?Nothing is bound. If any level of a record pattern fails its type test, the whole pattern fails and none of its (inner or outer) pattern variables are in scope in the matched block.
saying these in an interview costs you the question
- Thinking var imposes an extra type check (it only binds)
- Believing a failed inner pattern still binds the outer variables
- Assuming a null inner component matches a nested reference pattern
- Trying to omit some components in a nested level