Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A pattern variable is a local variable declared within a pattern matching expression that automatically extracts and binds a matched target to a specific type. It combines a type test, a variable declaration, and an implicit cast into a single, atomic language construct. Pattern variables are primarily utilized within type test patterns using the instanceof operator and switch statements/expressions.

Syntax Visualization

With instanceof:
// 'String s' is the type pattern. 's' is the pattern variable.
if (target instanceof String s) {
    System.out.println(s.toUpperCase());
}
With switch:
switch (target) {
    case String s -> System.out.println(s.toUpperCase());
    case Integer i -> System.out.println(i.intValue());
    default -> System.out.println("Unknown type");
}

Flow Scoping

The most defining characteristic of a pattern variable is its scope. Unlike traditional local variables governed strictly by lexical scoping (defined by curly braces {}), pattern variables are governed by flow scoping. Java explicitly utilizes flow scoping to introduce a new variable whose scope is determined by control flow, rejecting flow-sensitive typing (which narrows the type of an existing variable). A pattern variable is only in scope where the compiler can definitively prove that the pattern match has succeeded (definite assignment). Right-Hand Side of Logical Operators: Because the && operator short-circuits, the pattern variable is in scope on the right-hand side of the expression.
if (target instanceof String s && s.length() > 5) {
    // Valid: 's' is in scope because the RHS only evaluates if the LHS is true.
}

if (target instanceof String s || s.length() > 5) {
    // Compilation Error: 's' is NOT in scope on the RHS. 
    // If the LHS is false, the RHS evaluates, but the match failed.
}
Inverted Control Flow: Flow scoping extends beyond the immediate statement if the compiler detects an early exit (such as return or throw) upon a failed match.
if (!(target instanceof String s)) {
    return; // Exit if the match fails
}

// Valid: 's' is in scope for the remainder of the enclosing block.
// The compiler guarantees execution only reaches here if 'target' is a String.
System.out.println(s.toLowerCase());

Shadowing Rules

Pattern variables follow specific shadowing rules relative to the class and method hierarchy:
  1. Fields: A pattern variable can shadow a class-level field.
  2. Local Variables: A pattern variable cannot shadow a local variable declared in any enclosing block that is currently in scope. Attempting to declare a pattern variable with the same name as an existing local variable in an active enclosing scope results in a compilation error.

Modifiers

Pattern variables can be explicitly declared as final to prevent reassignment within their scope. Annotations can also be applied directly to the pattern variable declaration.
if (target instanceof final String s) {
    // s = "new string"; // Compilation Error: cannot assign a value to final variable s
}

if (target instanceof @NonNull String s) {
    // Pattern variable with an annotation
}
Master Java with Deep Grasping Methodology!Learn More