Primitive Types in Patterns, instanceof, and switch (JEP 507)
Pattern Matching has been revolutionizing Java for the past few versions. We’ve seen it with instanceof, then switch expressions, and then Record Patterns.
But there was always one limitation: it only worked with objects (reference types). You couldn’t use it directly with primitives like int, long, or double.
Java 25 changes that with Primitive Types in Patterns (JEP 507 - Preview).
Why do we need this?
Previously, if you wanted to switch on different types, you had to worry about whether you were dealing with a boxed type (like Integer) or a primitive (int).
// Pre-Java 25
Object obj = 42;
if (obj instanceof Integer i) {
// This works because 'obj' is an Integer (boxed)
}
// But you couldn't do this easily with direct primitives in data processing
How it works in Java 25
Now, instanceof and switch can handle direct primitive type patterns.
Type Testing with instanceof
You can now check if a value “matches” a primitive type. This is particularly useful when dealing with very large numbers or widened types.
long v = 42;
if (v instanceof byte b) {
System.out.println("It fits in a byte: " + b);
}
Wait, long behaves like a byte? Yes! In pattern matching, instanceof for primitives checks if the value can be represented exactly by the target type without loss of information. Since 42 fits in a byte, it matches. If v was 1000, it would not match byte b.
Switch with Primitives
The real power shines in switch expressions. You can now mix and match primitives and objects (if applicable) or simply switch on types for validation.
void process(long value) {
switch (value) {
case 1 -> System.out.println("One");
case byte b -> System.out.println("Small number: " + b);
case int i -> System.out.println("Medium number: " + i);
default -> System.out.println("Huge number");
}
}
If you call process(100), it matches case byte b. If you call process(100000), it matches case int i.
Unified Type System
This feature is a huge step towards unifying primitives and objects in Java. It allows we to write more generic data processing logic without constantly boxing and unboxing values or writing cumbersome range checks (e.g., if (v >= Byte.MIN_VALUE && v <= Byte.MAX_VALUE)).
Note: This is a Preview feature in Java 25, so you’ll need to enable preview flags to use it!