Record Patterns & Deconstruction
A record pattern matches a record and pulls its components straight out into named variables in one step — and because patterns nest, it can take an entire data structure apart inside a single instanceof or switch .
Learn Record Patterns & Deconstruction in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Before You Start
You should know records , pattern matching , and sealed classes . Record patterns are standard from Java 21 .
What You'll Learn
The Big Idea — Unpack the Box at the Door
💡 Analogy: A type pattern hands you a sealed box and says "this is a Point " — you still have to open it ( p.x() , p.y() ) to use what's inside. A record pattern unpacks the box at the door: Point(int x, int y) sets out the contents — x and y — ready to use. And if a box contains smaller boxes, nested patterns unpack those too, in one motion.
The result reads like the data's own shape, top to bottom, instead of a string of accessor calls.
1️⃣ Deconstructing in instanceof
Write the record's name followed by a pattern for each component: obj instanceof Point(int x, int y) . If obj is a Point , you immediately get x and y — no accessor calls, no cast. Each component sub-pattern can be an explicit type or var .
2️⃣ Nested Record Patterns
Because a record's components can be records, patterns nest. A Line made of two Point s can be torn down to its four numbers in a single pattern. Notice how the pattern's shape mirrors the data's shape exactly.
3️⃣ Record Patterns + Sealed = Exhaustive switch
This is the modern Java sweet spot. A sealed interface of record subtypes, processed by a switch whose arms are record patterns : each arm deconstructs its case, and the compiler proves you've covered them all — so no default .
4️⃣ Combining with Guards and Types
Component sub-patterns can be specific types, and the whole pattern can carry a when guard. Order matters: more specific patterns and guarded arms come first. Below, two String s, two equal ints, two ints, and a mixed pair are each handled distinctly.
🧠 Quick Recall
Predict the result before opening each answer.
Answer: 5 . The pattern matches and binds a=7 , b=2 , so a - b is 5 .
Answer: No. A record pattern must bind every component, so a 2-component record needs two sub-patterns. error: record pattern P does not match . Use P(var a, var b) .
Answer: "eq" . The guarded arm comes first and 4 equals 4, so it wins before the general two-ints arm is considered.
🎯 Your Turn — Deconstruct a Name
Use a record pattern in instanceof to pull out first and last and build a greeting.
🧩 Mini-Challenge — Sum a binary tree
Combine sealed records and nested record patterns to total a tree of integers recursively.
Common Errors
- ❌ Wrong number of component patterns. A record pattern must bind every component. Fix: one sub-pattern per component.
- ❌ Using record patterns on a non-record. Only records can be deconstructed this way. Fix: make the type a record, or use a type pattern.
- ❌ Incompatible component type. Point(String x, ...) when x is an int . Fix: match the declared type or use var .
- ❌ Broad pattern before a guarded one. The guarded arm becomes unreachable. Fix: guarded/specific arms first.
- ❌ Forgetting case null in a pattern switch. A record pattern won't match null . Fix: add case null if needed.
- ❌ Running on Java 20 or earlier. Record patterns are standard only from Java 21. Fix: compile with Java 21+.
Pro Tips
- 💡 Use var in deep nests to keep the pattern readable; reserve explicit types for the components you want to constrain.
- 💡 Let the pattern mirror the data. When the pattern's shape matches the record's shape, the code documents the structure for free.
- 💡 Pair with sealed types for exhaustiveness — the compiler becomes a checklist that catches every unhandled case.
- 💡 Great for parsing and ASTs. Expression trees, JSON nodes, and protocol messages all deconstruct cleanly.
📋 Quick Reference
Concept
Syntax
Note
instanceof deconstruct
o instanceof Point(int x, int y)
Binds x, y
switch deconstruct
case Point(int x, int y) -> ...
No cast, no accessors
var components
Point(var x, var y)
Types inferred
Nested pattern
Line(Point(var x, var y), ...)
Deep deconstruction
Typed component
Pair(Integer a, Integer b)
Constrains the type
Guarded
case P(var a, var b) when ...
Adds a boolean test
All components required
one sub-pattern each
Arity must match
Over sealed types
arm per record subtype
Exhaustive, no default
Null
case null -> ...
Pattern won't match null
Since
Java 21
JEP 440
📚 Resources / Keep Learning
- 📘 Oracle: Record Patterns — the official language guide.
- 📗 dev.java: Record Patterns — a guided tutorial.
- 📙 JEP 440: Record Patterns — the finalizing proposal.
❓ Frequently Asked Questions
🎉 Lesson Complete!
You can now deconstruct records inline with record patterns, nest them to take apart whole structures, use var for components, add when guards, and combine sealed types, records, and patterns into exhaustive switches.
Next up: Method References — the compact Type::method shorthand for lambdas.
Practice quiz
What does a record pattern like Point(int x, int y) do?
- Creates a new Point
- Calls a constructor
- Matches a Point and binds its components to x and y
- Compares two points
Answer: Matches a Point and binds its components to x and y. A record pattern matches the type and deconstructs it, binding each component to a variable in one step.
In which Java version did record patterns become a standard feature?
- Java 21
- Java 16
- Java 17
- Java 11
Answer: Java 21. Record patterns were finalized in Java 21 (JEP 440).
What is a nested record pattern?
- A record inside a method
- Two records in a switch
- A recursive method
- A pattern that deconstructs a record whose components are themselves records
Answer: A pattern that deconstructs a record whose components are themselves records. Line(Point(var x1, var y1), Point(var x2, var y2)) deconstructs nested records all the way down.
Can you use var for component bindings in a record pattern?
- No
- Yes — Point(var x, var y) infers each component type
- Only for the outer record
- Only in instanceof
Answer: Yes — Point(var x, var y) infers each component type. var is allowed for component bindings; the compiler infers each component's type.
Why do record patterns pair so well with sealed types?
- A switch can deconstruct and stay exhaustive with no default
- They run faster
- They reduce memory
- They allow inheritance
Answer: A switch can deconstruct and stay exhaustive with no default. Over a sealed hierarchy of records, a switch can deconstruct each case and the compiler proves exhaustiveness.
Without record patterns, how would you read a matched record's data?
- You couldn't
- Use reflection
- Bind the whole record, then call its accessor methods
- Cast to Object
Answer: Bind the whole record, then call its accessor methods. Previously you bound the record (case Point p) and called p.x(), p.y() yourself.
Can a record pattern include a guard with when?
- No
- Yes — case Pair(Integer a, Integer b) when a.equals(b) -> ...
- Only in instanceof
- Only without nesting
Answer: Yes — case Pair(Integer a, Integer b) when a.equals(b) -> .... Record patterns combine with when guards just like type patterns.
Do the component types in a record pattern have to exactly match the record's declared types?
- They can be anything
- They must be Object
- They must be primitives
- They must match or be valid sub-patterns
Answer: They must match or be valid sub-patterns. Each sub-pattern must be compatible with the record component's type (the same type, var, or a nested pattern).
What is the main readability benefit of record patterns?
- Shorter class names
- Deconstruct data inline instead of repeated accessor calls
- Automatic null checks
- Faster compilation
Answer: Deconstruct data inline instead of repeated accessor calls. You name the pieces you need right in the pattern, avoiding a chain of p.a().b() accessor calls.
Combining sealed + records + record patterns in a switch is often called...
- Reflection
- Lazy evaluation
- Data-oriented programming
- Generics
Answer: Data-oriented programming. Sealed types, records, and patterns together enable a data-oriented programming style.
Continue this course
- Previous: Sealed Classes
- Next: Method References