Primitive Types in Patterns (Preview)
Primitive type patterns let patterns use primitive types such as int, long, double and boolean, just like reference types. You can write case int m when m >= 90 in a switch, switch on a long or a boolean, and use instanceof to ask whether a value fits exactly in another type, as in value instanceof byte b. In Java 25 this is a preview feature (JEP 507, its third preview), so it must be enabled with --enable-preview, and details may still change. In this lesson, you will learn what primitive patterns add and what "exact" conversion means.
What It Adds
| Before | With primitive patterns |
|---|---|
switch worked on int, char, short, byte, strings and enums only | switch also works on long, float, double and boolean |
case labels on primitives could only be constants | case int m when m > 100 uses a type pattern with a guard |
instanceof worked only on references | x instanceof byte b tests whether x fits in a byte without loss |
| Narrowing casts silently lost data | Patterns match only when the conversion is exact |
Enabling the Preview
Without the flag, the compiler stops at the first primitive pattern:
Prim.java:5: error: primitive patterns are a preview feature and are disabled by default.
case int m when m >= 90 -> "A";
^
(use --enable-preview to enable primitive patterns)
1 errorRun the examples in this lesson with:
java --enable-preview --source 25 Prim.javaExample: Grades, Exact Fits and Boolean Switches
public class Prim {
static String grade(int marks) {
return switch (marks) {
case 100 -> "perfect";
case int m when m >= 90 -> "A";
case int m when m >= 75 -> "B";
case int m when m >= 0 -> "C";
case int m -> "invalid: " + m;
};
}
static void fits(int value) {
if (value instanceof byte b) {
System.out.println(value + " fits in a byte: " + b);
} else {
System.out.println(value + " does not fit in a byte");
}
}
static String exact(double d) {
return switch (d) {
case int i -> "whole number " + i;
case double x -> "has a fraction " + x;
};
}
public static void main(String[] args) {
System.out.println(grade(100));
System.out.println(grade(93));
System.out.println(grade(80));
System.out.println(grade(40));
System.out.println(grade(-5));
fits(100);
fits(300);
System.out.println(exact(42.0));
System.out.println(exact(42.5));
long big = 1L << 40;
System.out.println(big instanceof int);
boolean flag = true;
String word = switch (flag) {
case true -> "yes";
case false -> "no";
};
System.out.println(word);
}
}perfect
A
B
C
invalid: -5
100 fits in a byte: 100
300 does not fit in a byte
whole number 42
has a fraction 42.5
false
yesExplanation:
grade: a constant case (100) and guardedintpatterns in one switch. The last case,case int m, covers every remainingint, so the switch is exhaustive.fits:value instanceof byte bistrueonly if the value is between -128 and 127, so converting it loses nothing.300doesn't fit, so there is no silent wrap-around to44as a(byte)cast would give.exact:42.0converts to theint42 exactly, socase int imatches.42.5would lose its fraction, so it falls tocase double x.big instanceof int: 2⁴⁰ is too large for anint, so the answer isfalse.- The
booleanswitch is exhaustive withtrueandfalse, nodefaultneeded.
Example: Switching on a Long
public class Prim2 {
static String size(long bytes) {
return switch (bytes) {
case 0L -> "empty";
case long b when b < 1024 -> b + " B";
case long b when b < 1024 * 1024 -> (b / 1024) + " KB";
case long b -> (b / (1024 * 1024)) + " MB";
};
}
public static void main(String[] args) {
System.out.println(size(0));
System.out.println(size(512));
System.out.println(size(5000));
System.out.println(size(3_000_000));
int big = 16_777_217;
System.out.println(big instanceof float);
System.out.println(16_777_216 instanceof float);
System.out.println((float) big);
}
}empty
512 B
4 KB
2 MB
false
true
1.6777216E7Explanation: Before this feature, switch didn't accept a long at all. The second half shows a subtle point: a float has only 24 bits of precision, so it can't hold 16,777,217 exactly. The cast (float) big silently rounds it to 16,777,216, but big instanceof float tells you honestly that the conversion isn't exact.
Common Mistakes
Forgetting --enable-preview. The code doesn't compile.
Expecting a pattern to round. case int i doesn't match 42.5; it doesn't truncate like a cast.
Leaving a primitive switch non-exhaustive. With guarded patterns only, add an unguarded case int m (or default) at the end.
Interview Corner
What are primitive type patterns?
A preview feature in Java 25 (JEP 507) that allows primitive types in patterns. switch can then work on long, float, double and boolean, cases can use primitive type patterns with guards (case int m when m > 90), and instanceof can test primitives (x instanceof byte b). A primitive pattern matches only when the conversion is exact, with no loss of information, which makes it a safe alternative to narrowing casts. It requires --enable-preview.
Practice
- Easy: Write a switch on a
doubletemperature that returns "freezing", "cold", "warm" or "hot" using guardeddoublepatterns. - Harder: Write a method that receives a
longand returns the smallest type (byte,short,intorlong) that can hold it exactly, usinginstanceoftests.
Key Takeaways
Was this tutorial helpful?