Back to Java 24/25 Preview
Q2Question 2 of 8

What are Primitive Types in Patterns?

Key Concepts
  • JEP 507 extends pattern matching to primitive types: instanceof and switch now work with int, long, float, and double
  • Safe narrowing: if (longVal instanceof int i) succeeds only if the value fits in an int without loss
  • Switch can match on long, float, and double values with guards: case int i when i > 0 -> ...
  • Eliminates manual range checks and explicit casts when deciding how to store numeric values
  • Completes the pattern matching story: reference patterns (Java 16-21) plus primitive patterns (Java 24)
  • Exhaustiveness checking works with primitive patterns over sealed types
  • Preview in Java 24

Definition

Primitive types in patterns (JEP 507) extends instanceof and switch to match primitive types like int, long, and double with safe narrowing conversions.
  • Primitive patterns – instanceof and switch now match against primitive types, not just reference types.
  • Safe narrowing – if (longVal instanceof int i) succeeds only if the long value fits in an int without data loss.
  • Switch on long/double – switch can now match on long, float, and double values, not just int, String, and enum.
  • Guards – case int i when i > 0 -> ... combines type matching with conditions on primitive values.
  • Unification – completes the pattern matching model so it covers both reference and primitive types uniformly.

Before, the bank's routing system could only sort by customer name (reference types). After JEP 507, it can also sort by account number (int), balance (double), and transaction amount (long) directly in the routing rules.

Understanding the Concepts

What are Primitive Types in Patterns?

Primitive Types in Patterns (JEP 507, preview in Java 24) extends pattern matching so that instanceof and switch can match against primitive types and perform safe, range-checked conversions.

How does safe narrowing work?

When you write if (longVal instanceof int i), the pattern matches only if the long value fits within the int range (-2,147,483,648 to 2,147,483,647). If the value is outside that range, the pattern does not match and the if body is skipped.

JAVA
package com.bank.service;

public class AmountClassifier {

    public void classify(long amount) {
        if (amount instanceof int smallAmount) {
            System.out.println("Fits in int: " + smallAmount);
        } else {
            System.out.println("Too large for int: " + amount);
        }
    }
}
DIAGRAM
classify(50000)         → "Fits in int: 50000"
classify(3000000000L)   → "Too large for int: 3000000000"

How does switch on primitives work?

JAVA
public String classifyAmount(long amount) {
    return switch (amount) {
        case int i when i < 0       -> "Negative: " + i;
        case int i when i <= 100000 -> "Small transaction: " + i;
        case int i                  -> "Medium transaction: " + i;
        case long l                 -> "Large transaction: " + l;
    };
}

How is this different from manual range checking?

JAVA
// BEFORE: manual range check and cast
public void store(long amount) {
    if (amount >= Integer.MIN_VALUE && amount <= Integer.MAX_VALUE) {
        int intAmount = (int) amount;  // safe cast
        storeAsInt(intAmount);
    } else {
        storeAsLong(amount);
    }
}

// AFTER: primitive pattern (JEP 507)
public void store(long amount) {
    if (amount instanceof int intAmount) {
        storeAsInt(intAmount);  // safe: guaranteed to fit
    } else {
        storeAsLong(amount);
    }
}

What conversions are supported?

| Source | Pattern | Matches when |
|---|---|---|
| long | int i | Value fits in int range |
| double | float f | Value fits in float without precision loss |
| long | byte b | Value fits in byte range (-128 to 127) |
| int | short s | Value fits in short range |

What are common mistakes?

JAVA
// WRONG: assuming all long values match int pattern
long bigAmount = 5_000_000_000L;
if (bigAmount instanceof int i) {
    // This block is NEVER entered for 5 billion
    System.out.println(i);
}

// Pattern matching is SAFE: no ClassCastException, no overflow

What should a senior engineer know?

  • Primitive patterns complete the unification of pattern matching across all Java types.
  • Combined with sealed types and record patterns, you can now write exhaustive switches that handle both reference and primitive cases.
  • The JIT can optimize primitive pattern matches very efficiently since they reduce to range checks.
  • This feature is preview in Java 24; the API may change.

What are common interview follow-up questions?

  • Can you use primitive patterns in record deconstruction? (Yes, if a record component is a primitive, the pattern can narrow it.)
  • Does this replace manual casting? (For safe narrowing, yes. The pattern only matches when the cast would be lossless.)
  • What happens with floating point? (double instanceof float matches only if no precision is lost.)

Visual Overview

DIAGRAM
  Primitive Pattern Matching:

  long amount = 50000L;

  switch (amount) {
      case int i when i < 0       → "Negative"
      case int i when i <= 100000 → "Small"     ◀── matches (50000 fits in int)
      case int i                  → "Medium"
      case long l                 → "Large"
  }

  long bigAmount = 5_000_000_000L;

  switch (bigAmount) {
      case int i when i < 0       → skip (doesn't fit)
      case int i when i <= 100000 → skip (doesn't fit)
      case int i                  → skip (doesn't fit)
      case long l                 → "Large"    ◀── matches
  }

Key Takeaway

Primitive Types in Patterns (JEP 507, Java 24 preview) extends pattern matching to primitive types. You can now write if (longVal instanceof int i) for safe narrowing that only matches when the value fits without data loss. Switch expressions can match on long, float, and double with guards, not just int, String, and enum.

This eliminates manual range checks and explicit casts. Before JEP 507, checking if a long fits in an int required amount >= Integer.MIN_VALUE && amount <= Integer.MAX_VALUE followed by a cast. Now a single pattern match does both the check and the binding.

The feature completes the pattern matching story: reference patterns (Java 16-21) handle objects and records, and primitive patterns (Java 24) handle numeric types. Together, they give Java a unified pattern matching model across all types.

Remember one sentence: primitive patterns extend instanceof and switch to match int, long, and double with safe narrowing, completing the pattern matching unification.

---

Share
Use ← → arrow keys to navigate