Primitive Types in Patterns (Preview)

Naveen AnamaneniUpdated · 6 min read

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

BeforeWith primitive patterns
switch worked on int, char, short, byte, strings and enums onlyswitch also works on long, float, double and boolean
case labels on primitives could only be constantscase int m when m > 100 uses a type pattern with a guard
instanceof worked only on referencesx instanceof byte b tests whether x fits in a byte without loss
Narrowing casts silently lost dataPatterns match only when the conversion is exact

Enabling the Preview

Without the flag, the compiler stops at the first primitive pattern:

Compiler output
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 error

Run the examples in this lesson with:

Terminal
java --enable-preview --source 25 Prim.java

Example: Grades, Exact Fits and Boolean Switches

Prim.java
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);
    }
}
Terminal output
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
yes

Explanation:

  • grade: a constant case (100) and guarded int patterns in one switch. The last case, case int m, covers every remaining int, so the switch is exhaustive.
  • fits: value instanceof byte b is true only if the value is between -128 and 127, so converting it loses nothing. 300 doesn't fit, so there is no silent wrap-around to 44 as a (byte) cast would give.
  • exact: 42.0 converts to the int 42 exactly, so case int i matches. 42.5 would lose its fraction, so it falls to case double x.
  • big instanceof int: 2⁴⁰ is too large for an int, so the answer is false.
  • The boolean switch is exhaustive with true and false, no default needed.

Example: Switching on a Long

Prim2.java
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);
    }
}
Terminal output
empty
512 B
4 KB
2 MB
false
true
1.6777216E7

Explanation: 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

  1. Easy: Write a switch on a double temperature that returns "freezing", "cold", "warm" or "hot" using guarded double patterns.
  2. Harder: Write a method that receives a long and returns the smallest type (byte, short, int or long) that can hold it exactly, using instanceof tests.

Quick check: Primitive patterns

4 questions
1What does 300 instanceof byte b return?
2Which case matches 42.0 in switch (d) { case int i -> ...; case double x -> ...; }?
3What is needed to compile primitive patterns in Java 25?
4Why is 16_777_217 instanceof float false?

Key Takeaways

Was this tutorial helpful?

Lesson 462 of 482