Skip to content

How Java 26 Primitive Type Pattern Matching Works

Problem

I have code that processes different types of values. Pattern matching works great for objects, but primitive types require boxing:

Before Primitive Patterns
Object value = 42;
// Must match wrapper type, then unbox
if (value instanceof Integer i) {
int result = i * 2; // Unboxing happens here
System.out.println(result);
}
// Same problem in switch
switch (value) {
case Integer i -> processInt(i); // i is Integer, not int
case Double d -> processDouble(d); // d is Double, not double
default -> processOther(value);
}

Boxing creates objects. Unboxing extracts primitives. Both add overhead for simple type checks.

Environment

  • Java 26 (non-LTS)
  • --enable-preview required
  • Pattern matching scenarios

What Is Primitive Type Pattern Matching?

JEP 530 is the fourth preview of primitive types in patterns. It lets instanceof and switch work directly with primitive types.

With Primitive Patterns
Object value = 42;
// Match primitive int directly
if (value instanceof int i) {
int result = i * 2; // No boxing!
System.out.println(result);
}
// Switch with primitive patterns
switch (value) {
case int i -> processInt(i); // i is int, not Integer
case double d -> processDouble(d); // d is double, not Double
case long l -> processLong(l); // l is long, not Long
default -> processOther(value);
}

No wrapper objects. No boxing. No unboxing. The pattern binds directly to the primitive value.

How It Works

Boxing vs Primitive Pattern
Traditional Boxing:
┌─────────┐ ┌──────────┐ ┌─────────┐
│ int 42 │ → │ Integer │ → │ Match │
└─────────┘ └──────────┘ └─────────┘
(object allocation)
Primitive Pattern:
┌─────────┐ ┌─────────┐
│ int 42 │ → │ Match │
└─────────┘ └─────────┘
(no allocation)

The JVM checks the type and extracts the primitive in one step.

Practical Example

Here’s a more complete example showing various primitive patterns:

PrimitivePatternExample.java
public class PrimitivePatternExample {
public static void main(String[] args) {
Object[] values = {42, 3.14, 100L, "hello", true};
for (Object value : values) {
String description = describe(value);
System.out.println(value + " -> " + description);
}
}
static String describe(Object value) {
return switch (value) {
case int i -> "int: " + i + " (doubled: " + (i * 2) + ")";
case double d -> "double: " + d + " (squared: " + (d * d) + ")";
case long l -> "long: " + l;
case boolean b -> "boolean: " + b;
case String s -> "String: " + s;
default -> "Unknown type";
};
}
}

Output:

Output
42 -> int: 42 (doubled: 84)
3.14 -> double: 3.14 (squared: 9.8596)
100 -> long: 100
hello -> String: hello
true -> boolean: true

Why Fourth Preview?

Each preview refines the feature:

VersionFocus
JDK 23Initial preview
JDK 24Refined matching rules
JDK 25Edge case handling
JDK 26Stricter dominance checking in switch

Dominance checking means the compiler catches cases that would never match:

Dominance Checking
switch (value) {
case int i -> System.out.println("int");
case byte b -> System.out.println("byte"); // Error: dominated!
// byte values always match int first
}

The compiler now warns about these unreachable patterns.

How to Enable

Primitive patterns are a preview feature. Enable them:

Compile with Preview
javac --enable-preview --release 26 PrimitivePatternExample.java
Run with Preview
java --enable-preview PrimitivePatternExample

Production use requires waiting for the feature to exit preview status.

When to Use

Good scenarios:

  • Processing mixed-type collections
  • Type-safe parsing and validation
  • Data transformation pipelines
  • Cleaner conditional logic

Benefits:

  • No boxing overhead
  • More expressive code
  • Consistent pattern matching across all types
  • Better performance for numeric operations

Summary

In this post, I showed how Java 26’s primitive type pattern matching works. The key points are:

  • instanceof and switch can now match primitive types directly
  • No boxing/unboxing overhead
  • Fourth preview with refined dominance checking
  • Enable with --enable-preview
  • Wait for non-preview status before production use

Primitive patterns unify Java’s type system in pattern contexts. When they finalize, they’ll make type-safe code cleaner and more efficient.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments