This specification is not final and is subject to change. Use is subject to license terms.

Pattern Matching for instanceof

Changes to the Java® Language Specification • Version 16-internal+0-adhoc.gbierman.20201016

This document describes changes to the Java Language Specification to support pattern matching in instanceof expressions, a feature of Java SE 16. See JEP 394 for an overview of the feature.

These changes are the same as those in the second preview of pattern matching for instanceof in Java SE 15, except for some minor editorial changes and the following additional changes:

Changes are described with respect to existing sections of the JLS. New text is indicated like this and deleted text is indicated like this. Explanation and discussion, as needed, is set aside in grey boxes.

Chapter 1: Introduction

1.1 Organization of the Specification

...

Chapter 14 describes blocks and statements, which are based on C and C++, and patterns, which provide a means for describing the shape of data. The language has no goto statement, but includes labeled break and continue statements. Unlike C, the Java programming language requires boolean (or Boolean) expressions in control-flow statements, and does not convert types to boolean implicitly (except through unboxing), in the hope of catching more errors at compile time. A synchronized statement provides basic object-level monitor locking. A try statement can include catch and finally clauses to protect against non-local control transfers.

...

Chapter 4: Types, Values, and Variables

4.11 Where Types Are Used

Types are used in most kinds of declaration and in certain kinds of expression. Specifically, there are 16 type contexts where types are used:

Also, types are used as:

Finally, there are three special terms in the Java programming language which denote the use of a type:

...

4.12 Variables

4.12.3 Kinds of Variables

There are eight kinds of variables:

  1. A class variable is a field declared using the keyword static within a class declaration (8.3.1.1), or with or without the keyword static within an interface declaration (9.3).

    A class variable is created when its class or interface is prepared (12.3.2) and is initialized to a default value (4.12.5). The class variable effectively ceases to exist when its class or interface is unloaded (12.7).

  2. An instance variable is a field declared within a class declaration without using the keyword static (8.3.1.1).

    If a class T has a field a that is an instance variable, then a new instance variable a is created and initialized to a default value (4.12.5) as part of each newly created object of class T or of any class that is a subclass of T (8.1.4). The instance variable effectively ceases to exist when the object of which it is a field is no longer referenced, after any necessary finalization of the object (12.6) has been completed.

  3. Array components are unnamed variables that are created and initialized to default values (4.12.5) whenever a new object that is an array is created (10, 15.10.2). The array components effectively cease to exist when the array is no longer referenced.

  4. Method parameters (8.4.1) name argument values passed to a method.

    For every parameter declared in a method declaration, a new parameter variable is created each time that method is invoked (15.12). The new variable is initialized with the corresponding argument value from the method invocation. The method parameter effectively ceases to exist when the execution of the body of the method is complete.

  5. Constructor parameters (8.8.1) name argument values passed to a constructor.

    For every parameter declared in a constructor declaration, a new parameter variable is created each time a class instance creation expression (15.9) or explicit constructor invocation (8.8.7) invokes that constructor. The new variable is initialized with the corresponding argument value from the creation expression or constructor invocation. The constructor parameter effectively ceases to exist when the execution of the body of the constructor is complete.

  6. Lambda parameters (15.27.1) name argument values passed to a lambda expression body (15.27.2).

    For every parameter declared in a lambda expression, a new parameter variable is created each time a method implemented by the lambda body is invoked (15.12). The new variable is initialized with the corresponding argument value from the method invocation. The lambda parameter effectively ceases to exist when the execution of the lambda expression body is complete.

  7. An exception parameter is created each time an exception is caught by a catch clause of a try statement (14.20).

    The new variable is initialized with the actual object associated with the exception (11.3, 14.18). The exception parameter effectively ceases to exist when execution of the block associated with the catch clause is complete.

  8. Local variables are declared by local variable declaration statements (14.4), for statements (14.14), try-with-resources statements (14.20.3), or patterns (14.30).

    Whenever the flow of control enters a block (14.2), or for statement (14.14), or try-with-resources statement (14.20.3), a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block, or for statement, or try-with-resources statement.

    A local variable declaration statement or for statement may contain an expression which initializes the variable. A try-with-resources statement always contains expressions to intialize any local variables declared in its resource specification. In all cases, the The local variable with an initializing expression is not initialized, however, until the local variable declaration statement that declares it is executed.

    Pattern variables are local variables declared in patterns (14.30). Pattern variables do not have initializers but are assigned a value by the process of pattern matching (14.30.3). This process is conditional; a pattern variable is only assigned a value if the pattern match succeeds. For this reason, pattern variables require special rules restricting their use (6.3).

    (The rules of definite assignment (16) prevent the value of a local variable that is not a pattern variable from being used before it has been initialized or otherwise assigned a value.) (The rules of scoping for pattern variables (6.3.1) prevent the value of a pattern variable from being used when it has not been assigned a value.) The local variable effectively ceases to exist when the execution of the block, or for for statement, or try-with-resources statement is complete.

Were it not for one exceptional situation, a local variable could always be regarded as being created when its local variable declaration statement is executed. The exceptional situation involves the switch statement (14.11), where it is possible for control to enter a block but bypass execution of a local variable declaration statement. Because of the restrictions imposed by the rules of definite assignment (16), however, the local variable declared by such a bypassed local variable declaration statement cannot be used before it has been definitely assigned a value by an assignment expression (15.26).

Example 4.12.3-1. Different Kinds of Variables

class Point {
    static int numPoints;   // numPoints is a class variable
    int x, y;               // x and y are instance variables
    int[] w = new int[10];  // w[0] is an array component
    int setX(int x) {       // x is a method parameter
        int oldx = this.x;  // oldx is a local variable
        this.x = x;
        return oldx;
    }
    boolean equalAtX(Object o) {
        if (o instanceof Point p)  // p is a pattern variable
            return this.x == p.x;
        else
            return false;
    }
}

4.12.4 final Variables

A variable can be declared final. A final variable may only be assigned to once. It is a compile-time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment (16).

Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.

A blank final is a final variable whose declaration lacks an initializer.

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (15.29). Whether a variable is a constant variable or not may have implications with respect to class initialization (12.4.1), binary compatibility (13.1), reachability (14.22), and definite assignment (16.1.1).

Three kinds of variable are implicitly declared final: a field of an interface (9.3), a local variable declared as a resource of a try-with-resources statement (14.20.3), and an exception parameter of a multi-catch clause (14.20). An exception parameter of a uni-catch clause is never implicitly declared final, but may be effectively final.

Example 4.12.4-1. Final Variables

Declaring a variable final can serve as useful documentation that its value will not change and can help avoid programming errors. In this program:

class Point {
    int x, y;
    int useCount;
    Point(int x, int y) { this.x = x; this.y = y; }
    static final Point origin = new Point(0, 0);
}

the class Point declares a final class variable origin. The origin variable holds a reference to an object that is an instance of class Point whose coordinates are (0, 0). The value of the variable Point.origin can never change, so it always refers to the same Point object, the one created by its initializer. However, an operation on this Point object might change its state - for example, modifying its useCount or even, misleadingly, its x or y coordinate.

Certain variables that are not declared final are instead considered effectively final:

If a variable is effectively final, adding the final modifier to its declaration will not introduce any compile-time errors. Conversely, a local variable or parameter that is declared final in a valid program becomes effectively final if the final modifier is removed.

4.12.5 Initial Values of Variables

Every variable in a program must have a value before its value is used:

Example 4.12.5-1. Initial Values of Variables

class Point {
    static int npoints;
    int x, y;
    Point root;
}

class Test {
    public static void main(String[] args) {
        System.out.println("npoints=" + Point.npoints);
        Point p = new Point();
        System.out.println("p.x=" + p.x + ", p.y=" + p.y);
        System.out.println("p.root=" + p.root);
    }
}

This program prints:

npoints=0
p.x=0, p.y=0
p.root=null

illustrating the default initialization of npoints, which occurs when the class Point is prepared (12.3.2), and the default initialization of x, y, and root, which occurs when a new Point is instantiated. See 12 for a full description of all aspects of loading, linking, and initialization of classes and interfaces, plus a description of the instantiation of classes to make new class instances.

Chapter 5: Conversions and Contexts

5.5 Casting Contexts

Casting contexts allow the operand of a cast expression (15.16) to be converted to the type explicitly named by the cast operator, the first operand of a type instanceof operator (15.20.2) to be converted to the type given by the second operand, and the first operand of a pattern instanceof operator (15.20.2) to be converted to the type of the pattern given by the second operand (15.30.1).. Compared to assignment contexts and invocation contexts, casting contexts allow the use of more of the conversions defined in 5.1, and allow more combinations of those conversions.

...

Chapter 6: Names

6.1 Declarations

A declaration introduces an entity into a program and includes an identifier (3.8) that can be used in a name to refer to this entity. The identifier is constrained to be a type identifier when the entity being introduced is a class, interface, or type parameter.

A declared entity is one of the following:

Constructors (8.8) are also introduced by declarations, but use the name of the class in which they are declared rather than introducing a new name.

...

6.3 Scope of a Declaration

The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to using a simple name, provided it is not shadowed (6.4.1).

A declaration is said to be in scope at a particular point in a program if and only if the declaration's scope includes that point.

The scope of the declaration of an observable top level package (7.4.3) is all observable compilation units associated with modules to which the package is uniquely visible (7.4.3).

The declaration of a package that is not observable is never in scope.

The declaration of a subpackage is never in scope.

The package java is always in scope.

The scope of a type imported by a single-type-import declaration (7.5.1) or a type-import-on-demand declaration (7.5.2) is the module declaration (7.7) and all the class and interface type declarations (7.6) of the compilation unit in which the import declaration appears, as well as any annotations on the module declaration or package declaration of the compilation unit.

The scope of a member imported by a single-static-import declaration (7.5.3) or a static-import-on-demand declaration (7.5.4) is the module declaration and all the class and interface type declarations of the compilation unit in which the import declaration appears, as well as any annotations on the module declaration or package declaration of the compilation unit.

The scope of a top level type (7.6) is all type declarations in the package in which the top level type is declared.

The scope of a declaration of a member m declared in or inherited by a class type C (8.1.6) is the entire body of C, including any nested type declarations.

The scope of a declaration of a member m declared in or inherited by an interface type I (9.1.4) is the entire body of I, including any nested type declarations.

The scope of an enum constant C declared in an enum type T is the body of T, and any case label of a switch statement whose expression is of enum type T (14.11).

The scope of a formal parameter of a method (8.4.1), constructor (8.8.1), or lambda expression (15.27) is the entire body of the method, constructor, or lambda expression.

The scope of a class's type parameter (8.1.2) is the type parameter section of the class declaration, the type parameter section of any superclass or superinterface of the class declaration, and the class body.

The scope of an interface's type parameter (9.1.2) is the type parameter section of the interface declaration, the type parameter section of any superinterface of the interface declaration, and the interface body.

The scope of a method's type parameter (8.4.4) is the entire declaration of the method, including the type parameter section, but excluding the method modifiers.

The scope of a constructor's type parameter (8.8.4) is the entire declaration of the constructor, including the type parameter section, but excluding the constructor modifiers.

The scope of a local class declaration immediately enclosed by a block (14.2) is the rest of the immediately enclosing block, including its own class declaration.

The scope of a local class declaration immediately enclosed by a switch block statement group (14.11) is the rest of the immediately enclosing switch block statement group, including its own class declaration.

The scope of a local variable declaration in a block (14.4) is the rest of the block in which the declaration appears, starting with its own initializer and including any further declarators to the right in the local variable declaration statement.

The scope of a local variable declared in the ForInit part of a basic for statement (14.14.1) includes all of the following:

The scope of a local variable declared in the FormalParameter part of an enhanced for statement (14.14.2) is the contained Statement.

The scope of a parameter of an exception handler that is declared in a catch clause of a try statement (14.20) is the entire block associated with the catch.

The scope of a variable declared in the ResourceSpecification of a try-with-resources statement (14.20.3) is from the declaration rightward over the remainder of the ResourceSpecification and the entire try block associated with the try-with-resources statement.

The translation of a try-with-resources statement implies the rule above.

Example 6.3-1. Scope of Type Declarations

These rules imply that declarations of class and interface types need not appear before uses of the types. In the following program, the use of PointList in class Point is valid, because the scope of the class declaration PointList includes both class Point and class PointList, as well as any other type declarations in other compilation units of package points.

package points;
class Point {
    int x, y;
    PointList list;
    Point next;
}

class PointList {
    Point first;
}

Example 6.3-2. Scope of Local Variable Declarations

The following program causes a compile-time error because the initialization of local variable x is within the scope of the declaration of local variable x, but the local variable x does not yet have a value and cannot be used. The field x has a value of 0 (assigned when Test1 was initialized) but is a red herring since it is shadowed (6.4.1) by the local variable x.

class Test1 {
    static int x;
    public static void main(String[] args) {
        int x = x;
    }
}

The following program does compile:

class Test2 {
    static int x;
    public static void main(String[] args) {
        int x = (x=2)*2;
        System.out.println(x);
    }
}

because the local variable x is definitely assigned (16) before it is used. It prints:

4

In the following program, the initializer for three can correctly refer to the variable two declared in an earlier declarator, and the method invocation in the next line can correctly refer to the variable three declared earlier in the block.

class Test3 {
    public static void main(String[] args) {
        System.out.print("2+1=");
        int two = 2, three = two + 1;
        System.out.println(three);
    }
}

This program produces the output:

2+1=3

A variable declared in a pattern is known as a pattern variable (14.30). Pattern variables differ from other local variables in that they are automatically initialized to a value given by the result of pattern matching (14.30.3). This process is conditional; a pattern variable is only initialized to a value if the pattern match succeeds.

Accordingly the scope of pattern variables is carefully defined so that a pattern variable is only in scope at those program points where pattern matching will have succeeded and the pattern variable will have been definitely assigned a value. Put another way, accessing a pattern variable where pattern matching can not be guaranteed to have succeeded is not possible and will result in a compile-time error.

In this sense, the scope of a pattern variable is a flow dependent concept similar to definite assignment (Chapter 16). The rules that are defined in the rest of this section deliberately have a similar form to those used in Chapter 16.

The scope of a pattern variable is determined by considering the innermost enclosing statement S that contains the pattern variable declaration. The overall scope of a pattern variable V is defined to be (i) those expressions and statements contained in S where V is definitely matched; and (ii) if S is immediately contained by a statement Q, those statements following S contained by Q where V is definitely matched; and (iii) if S is immediately contained by a block, those statements following S contained by that block where V is definitely matched.

The remainder of this section is devoted to a precise explanation of the words "definitely matched at", for which we define three auxiliary technical terms:

The analysis takes into account the structure of statements and expressions, with a special treatment for the boolean expression operators and certain statement forms.

The simplest example is that the pattern variable s is introduced by the expression a instanceof String s when true. In other words, if the value of the expression is true then the pattern matching must have succeeded, and thus the pattern variable must have been assigned a value.

In contrast, the pattern variable t is introduced by the expression !(b instanceof Integer t) when false. This is because the pattern matching could only have succeeded if the value of the expression is false.

Pattern variables can, in certain circumstances, be introduced by a statement. Further details are given in 6.3.2.

6.3.1 Pattern Declaration Scopes and Expressions

Only certain boolean expressions can introduce a new pattern variable into scope. If an expression is not a logical complement expression, conditional-and expression, conditional-or expression, conditional expression, instanceof operator, or a parenthesized expression then no rules apply regarding the introduction of pattern variables.

6.3.1.1 Conditional-And Operator &&

The following rules apply to a conditional-and expression (15.23):

The first rule rules out the possibility of a pattern variable being implicitly assigned a value more than once by pattern matching. Pattern variables are implicitly final by design.

if ((a instanceof String s) && (b instanceof String s)) {
    System.out.println(s);   // Not allowed
}

The second rule means that a pattern variable introduced by the left-hand operand of a conditional-and operator is in scope, and can therefore be used, in the right-hand operand. This allows for expressions such as x instanceof String s && s.length()>0.

6.3.1.2 Conditional-Or Operator ||

The following rules apply to a conditional-or expression (15.24):

6.3.1.3 Logical Complement Operator !

The following rules apply to a logical complement expression (15.15.6):

6.3.1.4 Conditional Operator ? :

The following rules apply to a conditional expression a ? b : c (15.25):

6.3.1.5 instanceof Operator

The following rule applies to an instanceof expression (15.20.2):

Note that no pattern variable is introduced by an expression a instanceof p when false.

6.3.1.6 switch Expressions

The following rule covers the switch expression (15.28).

6.3.1.7 Parenthesized Expressions

The following rules cover the parenthesized expression (15.8.5).

6.3.2 Pattern Declaration Scopes and Statements

Only a few statements play a significant role in determining the scope of pattern variables.

The scope of pattern variables declared in subexpressions contained within if, while, do, and for statements can, in certain circumstances, include other contained substatements. Here is an example:

if (x instanceof String s) {
    // String s in scope for this block
    // No explicit cast needed here!
    ...
    System.out.println("The string value was: " + s);
} else {
    // String s not in scope here
    System.out.println(s); // Compile-time error!
}

In certain constrained circumstances, a pattern variable can be introduced by a statement. In this case, the pattern variable is in scope at the following statements in the enclosing block. Here is an example:

public void RequiresAString(Object o) {
    if (!(o instanceof String s)) {
        throw new IllegalArgumentException();
    }
    // Only reachable if the pattern match succeeded
    // String s is thus in scope for the rest of the block
    System.out.println("The parameter string was: " + s);
    ...
}
6.3.2.1 Blocks

The following rule applies to a block statement S contained in a block that is not a switch block:

6.3.2.2 if Statements

The following rules apply to a statement if (e) S (14.9.1):

The second rule makes use of the notion of 'cannot complete normally' (14.21), which itself makes use of the concept of a constant expression (15.29). This means that calculating the scope of a pattern variable may require determining whether a simple name, or a qualified name of the form TypeName. Identifier, refers to a constant variable. As pattern variables can never refer to a constant variable, there is no circularity.

The following rules apply to a statement if (e) S else T (14.9.2):

These rules highlight the flow-like nature of scoping for pattern variables. In the following statement:

if (e instanceof String s) {
  counter += s.length();
} else {
  ...   // s not in scope
}

The pattern variable s is introduced by the instanceof operator and is in scope in the first contained statement (the one before the else keyword), but it is not in scope in the second contained statement (the one after the else keyword).

Moreover, combined with the treatment for the boolean expressions, the scope of pattern variables is robust against code refactorings that exploit the familar boolean logical equivalences. For example, the previous code can be rewritten as:

if (!(e instanceof String s)) {
  ...   // s not in scope
} else {
  counter += s.length();
}

And, furthermore, can be rewritten as:

if (!!(e instanceof String s)) {
  counter += s.length();
} else {
  ...   // s not in scope
}
6.3.2.3 while Statements

The following rules apply to a statement while (e) S (14.12):

6.3.2.4 do Statements

The following rule applies to a statement do S while (e) (14.13):

6.3.2.5 for Statements

The following rules cover the basic for statement (14.14.1). Since the enhanced for statement (14.14.2) is defined by translation to a basic for statement, no special rules need to be provided for it.

6.3.2.6 switch Statements

The following rule covers the switch statement (14.11).

6.3.2.7 Labeled Statements

The following rule covers the labeled statement (14.7).

6.4 Shadowing and Obscuring

A local variable (14.4, 14.14, 14.20.3, 14.30), formal parameter (8.4.1, 15.27.1), exception parameter (14.20), and local class (14.3) can only be referred to using a simple name, not a qualified name (6.2).

Some declarations are not permitted within the scope of a local variable, formal parameter, exception parameter, or local class declaration because it would be impossible to distinguish between the declared entities using only simple names.

For example, if the name of a formal parameter of a method could be redeclared as the name of a local variable in the method body, then the local variable would shadow the formal parameter and there would be no way to refer to the formal parameter - an undesirable outcome.

It is a compile-time error if the name of a formal parameter is used to declare a new variable within the body of the method, constructor, or lambda expression, unless the new variable is declared within a class declaration contained by the method, constructor, or lambda expression.

It is a compile-time error if the name of a local variable v is used to declare a new variable within the scope of v, unless the new variable is declared within a class whose declaration is within the scope of v.

It is a compile-time error if the name of an exception parameter is used to declare a new variable within the Block of the catch clause, unless the new variable is declared within a class declaration contained by the Block of the catch clause.

It is a compile-time error if the name of a local class C is used to declare a new local class within the scope of C, unless the new local class is declared within another class whose declaration is within the scope of C.

These rules allow redeclaration of a variable or local class in nested class declarations that occur in the scope of the variable or local class; such nested class declarations may be local classes (14.3) or anonymous classes (15.9). Thus, the declaration of a formal parameter, local variable, or local class may be shadowed in a class declaration nested within a method, constructor, or lambda expression; and the declaration of an exception parameter may be shadowed in a class declaration nested within the Block of the catch clause.

There are two design alternatives for handling name clashes created by lambda parameters and other variables declared in lambda expressions. One is to mimic class declarations: like local classes, lambda expressions introduce a new "level" for names, and all variable names outside the expression can be redeclared. Another is a "local" strategy: like catch clauses, for loops, and blocks, lambda expressions operate at the same "level" as the enclosing context, and local variables outside the expression cannot be shadowed. The above rules use the local strategy; there is no special dispensation that allows a variable declared in a lambda expression to shadow a variable declared in an enclosing method.

Note that the rule for local classes does not make an exception for a class of the same name declared within the local class itself. However, this case is prohibited by a separate rule: a class cannot have the same name as a class that encloses it (8.1).

Example 6.4-1. Attempted Shadowing Of A Local Variable

Because a declaration of an identifier as a local variable of a method, constructor, or initializer block must not appear within the scope of a parameter or local variable of the same name, a compile-time error occurs for the following program:

class Test1 {
    public static void main(String[] args) {
        int i;
        for (int i = 0; i < 10; i++)
            System.out.println(i);
    }
}

This restriction helps to detect some otherwise very obscure bugs. A similar restriction on shadowing of members by local variables was judged impractical, because the addition of a member in a superclass could cause subclasses to have to rename local variables. Related considerations make restrictions on shadowing of local variables by members of nested classes, or on shadowing of local variables by local variables declared within nested classes unattractive as well.

Hence, the following program compiles without error:

class Test2 {
    public static void main(String[] args) {
        int i;
        class Local {
            {
                for (int i = 0; i < 10; i++)
                    System.out.println(i);
            }
        }
        new Local();
    }
}

On the other hand, local variables with the same name may be declared in two separate blocks or for statements, neither of which contains the other:

class Test3 {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++)
            System.out.print(i + " ");
        for (int i = 10; i > 0; i--)
            System.out.print(i + " ");
        System.out.println();
    }
}

This program compiles without error and, when executed, produces the output:

0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1

This style is also common with pattern matching, where repeated type test patterns often employ the same pattern name:

class Test4 {
    class Point {
        int x, y;
    }
    public static void test(Object a, Object b, Object c) {
        if (a instanceof Point p) {
            System.out.print("a is a point (" + p.x + ", " + p.y);
        }
        if (b instanceof Point p){
            System.out.print("b is a point (" + p.x + ", " + p.y);
        } else if (c instanceof Point p) {
            System.out.print("c is a point (" + p.x + ", " + p.y);
        }
        System.out.println();
    }
}

However, pattern variables are not allowed to shadow other pattern variables; a compile-time error occurs for the following program:

class Test5 {
    public static void test(Object a, Object b, Object c) {
        if (a instanceof Point p) {
            System.out.print("a is a point (" + p.x + ", " + p.y);
            if (b instanceof Point p){
                System.out.print("b is a point (" + p.x + ", " + p.y); // Error
            }
        }
        System.out.println();
    }
}

As pattern variables are local variables, they are not allowed to shadow local variables; a compile-time error occurs for the following program:

class Test6 {
    class Point {
        int x, y;
        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    public static void test(Object o) {
        Point p = new Point(0,0);
        if (o instanceof Point p)
            System.out.println("I get your point");
    }
}

6.5 Determining the Meaning of a Name

6.5.1 Syntactic Classification of a Name According to Context

A name is syntactically classified as a ModuleName in these contexts:

A name is syntactically classified as a PackageName in these contexts:

A name is syntactically classified as a TypeName in these contexts:

The extraction of a TypeName from the identifiers of a ReferenceType in the 16 contexts above is intended to apply recursively to all sub-terms of the ReferenceType, such as its element type and any type arguments.

For example, suppose a field declaration uses the type p.q.Foo[]. The brackets of the array type are ignored, and the term p.q.Foo is extracted as a dotted sequence of Identifiers to the left of the brackets in an array type, and classified as a TypeName. A later step determines which of p, q, and Foo is a type name or a package name.

As another example, suppose a cast operator uses the type p.q.Foo<? extends String>. The term p.q.Foo is again extracted as a dotted sequence of Identifier terms, this time to the left of the < in a parameterized type, and classified as a TypeName. The term String is extracted as an Identifier in an extends clause of a wildcard type argument of a parameterized type, and classified as a TypeName.

A name is syntactically classified as an ExpressionName in these contexts:

A name is syntactically classified as a MethodName in this context:

A name is syntactically classified as a PackageOrTypeName in these contexts:

A name is syntactically classified as an AmbiguousName in these contexts:

The effect of syntactic classification is to restrict certain kinds of entities to certain parts of expressions:

6.5.2 Reclassification of Contextually Ambiguous Names

An AmbiguousName is then reclassified as follows.

If the AmbiguousName is a simple name, consisting of a single Identifier:

...

Chapter 9: Interfaces

9.6 Annotation Types

9.6.4 Predefined Annotation Types

9.6.4.1 @Target

An annotation of type java.lang.annotation.Target is used on the declaration of an annotation type T to specify the contexts in which T is applicable. java.lang.annotation.Target has a single element, value, of type java.lang.annotation.ElementType[], to specify contexts.

Annotation types may be applicable in declaration contexts, where annotations apply to declarations, or in type contexts, where annotations apply to types used in declarations and expressions.

There are nine declaration contexts, each corresponding to an enum constant of java.lang.annotation.ElementType:

  1. Module declarations (7.7)

    Corresponds to java.lang.annotation.ElementType.MODULE

  2. Package declarations (7.4.1)

    Corresponds to java.lang.annotation.ElementType.PACKAGE

  3. Type declarations: class, interface, enum, and annotation type declarations (8.1.1, 9.1.1, 8.5, 9.5, 8.9, 9.6)

    Corresponds to java.lang.annotation.ElementType.TYPE

    Additionally, annotation type declarations correspond to java.lang.annotation.ElementType.ANNOTATION_TYPE

  4. Method declarations (including elements of annotation types) (8.4.3, 9.4, 9.6.1)

    Corresponds to java.lang.annotation.ElementType.METHOD

  5. Constructor declarations (8.8.3)

    Corresponds to java.lang.annotation.ElementType.CONSTRUCTOR

  6. Type parameter declarations of generic classes, interfaces, methods, and constructors (8.1.2, 9.1.2, 8.4.4, 8.8.4)

    Corresponds to java.lang.annotation.ElementType.TYPE_PARAMETER

  7. Field declarations (including enum constants) (8.3.1, 9.3, 8.9.1)

    Corresponds to java.lang.annotation.ElementType.FIELD

  8. Formal and exception parameter declarations (8.4.1, 9.4, 14.20)

    Corresponds to java.lang.annotation.ElementType.PARAMETER

  9. Local variable declarations (including loop variables of for statements, and resource variables of try-with-resources statements, and pattern variables) (14.4, 14.14, 14.14.1, 14.14.2, 14.20.3, 14.30)

    Corresponds to java.lang.annotation.ElementType.LOCAL_VARIABLE

There are 16 type contexts (4.11), all represented by the enum constant TYPE_USE of java.lang.annotation.ElementType.

It is a compile-time error if the same enum constant appears more than once in the value element of an annotation of type java.lang.annotation.Target.

If an annotation of type java.lang.annotation.Target is not present on the declaration of an annotation type T, then T is applicable in all nine declaration contexts and in all 16 type contexts.

9.7.4 Where Annotations May Appear

A declaration annotation is an annotation that applies to a declaration, and whose own type is applicable in the declaration context (9.6.4.1) represented by that declaration; or an annotation that applies to a class, interface, enum, annotation type, or type parameter declaration, and whose own type is applicable in type contexts (4.11).

A type annotation is an annotation that applies to a type (or any part of a type), and whose own type is applicable in type contexts.

For example, given the field declaration:

@Foo int f;

@Foo is a declaration annotation on f if Foo is meta-annotated by @Target(ElementType.FIELD), and a type annotation on int if Foo is meta-annotated by @Target(ElementType.TYPE_USE). It is possible for @Foo to be both a declaration annotation and a type annotation simultaneously.

Type annotations can apply to an array type or any component type thereof (10.1). For example, assuming that A, B, and C are annotation types meta-annotated with @Target(ElementType.TYPE_USE), then given the field declaration:

@C int @A [] @B [] f;

@A applies to the array type int[][], @B applies to its component type int[], and @C applies to the element type int. For more examples, see 10.2.

An important property of this syntax is that, in two declarations that differ only in the number of array levels, the annotations to the left of the type refer to the same type. For example, @C applies to the type int in all of the following declarations:

@C int f;
@C int[] f;
@C int[][] f;

It is customary, though not required, to write declaration annotations before all other modifiers, and type annotations immediately before the type to which they apply.

It is possible for an annotation to appear at a syntactic location in a program where it could plausibly apply to a declaration, or a type, or both. This can happen in any of the five declaration contexts where modifiers immediately precede the type of the declared entity:

The grammar of the Java programming language unambiguously treats annotations at these locations as modifiers for a declaration (8.3), but that is purely a syntactic matter. Whether an annotation applies to the declaration or to the type of the declared entity - and thus, whether the annotation is a declaration annotation or a type annotation - depends on the applicability of the annotation's type:

In the second and third cases above, the type which is closest to the annotation is determined as follows:

It is a compile-time error if an annotation of type T is syntactically a modifier for:

Five of these nine clauses mention "... or type contexts" because they characterize the five syntactic locations where an annotation could plausibly apply either to a declaration or to the type of a declared entity. Furthermore, two of the nine clauses - for class, interface, enum, and annotation type declarations, and for type parameter declarations - mention "... or type contexts" because it may be convenient to apply an annotation whose type is meta-annotated with @Target(ElementType.TYPE_USE) (thus, applicable in type contexts) to a type declaration.

A type annotation is admissible if both of the following are true:

The intuition behind the second clause is that if Outer.this is legal in a nested class enclosed by Outer, then Outer may be annotated because it represents the type of some object at run time. On the other hand, if Outer.this is not legal - because the class where it appears has no enclosing instance of Outer at run time - then Outer may not be annotated because it is logically just a name, akin to components of a package name in a fully qualified type name.

For example, in the following program, it is not possible to write A.this in the body of B, as B has no lexically enclosing instances (8.5.1). Therefore, it is not possible to apply @Foo to A in the type A.B, because A is logically just a name, not a type.

@Target(ElementType.TYPE_USE)
@interface Foo {}

class A {
    static class B {}
}

@Foo A.B x;  // Illegal 

On the other hand, in the following program, it is possible to write C.this in the body of D. Therefore, it is possible to apply @Foo to C in the type C.D, because C represents the type of some object at run time.

@Target(ElementType.TYPE_USE)
@interface Foo {}

class Test {
    static class C {
        class D {}
    }

    @Foo C.D x;  // Legal 
}

It is a compile-time error if an annotation of type T applies to the outermost level of a type in a type context, and T is not applicable in type contexts or the declaration context (if any) which occupies the same syntactic location.

It is a compile-time error if an annotation of type T applies to a part of a type (that is, not the outermost level) in a type context, and T is not applicable in type contexts.

It is a compile-time error if an annotation of type T applies to a type (or any part of a type) in a type context, and T is applicable in type contexts, and the annotation is not admissible.

For example, assume an annotation type TA which is meta-annotated with just @Target(ElementType.TYPE_USE). The terms @TA java.lang.Object and java.@TA lang.Object are illegal because the simple name to which @TA is closest is classified as a package name. On the other hand, java.lang.@TA Object is legal.

Note that the illegal terms are illegal "everywhere". The ban on annotating package names applies broadly: to locations which are solely type contexts, such as class ... extends @TA java.lang.Object {...}, and to locations which are both declaration and type contexts, such as @TA java.lang.Object f;. (There are no locations which are solely declaration contexts where a package name could be annotated, as class, package, and type parameter declarations use only simple names.)

If TA is additionally meta-annotated with @Target(ElementType.FIELD), then the term @TA java.lang.Object is legal in locations which are both declaration and type contexts, such as a field declaration @TA java.lang.Object f;. Here, @TA is deemed to apply to the declaration of f (and not to the type java.lang.Object) because TA is applicable in the field declaration context.

Chapter 14: Blocks and Statements and Patterns

14.4 Local Variable Declaration Statements

A local variable declaration statement declares one or more local variable names.

LocalVariableDeclarationStatement:
LocalVariableDeclaration ;
LocalVariableDeclaration:
{VariableModifier} LocalVariableType VariableDeclaratorList
LocalVariableType:
UnannType
var

See 8.3 for UnannType. The following productions from 4.3, 8.3, and 8.4.1 are shown here for convenience:

VariableModifier:
Annotation
final
VariableDeclaratorList:
VariableDeclarator {, VariableDeclarator}
VariableDeclarator:
VariableDeclaratorId [= VariableInitializer]
VariableDeclaratorId:
Identifier [Dims]
Dims:
{Annotation} [ ] {{Annotation} [ ]}
VariableInitializer:
Expression
ArrayInitializer

Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.

Apart from local variable declaration statements, a local variable can be declared by the header of a basic for statement (14.1414.14.1), an enhanced for statement (14.14.2), or a try-with-resources statement (14.20.3), or a pattern (14.30).

The rules for annotation modifiers on a local variable declaration are specified in 9.7.4 and 9.7.5.

It is a compile-time error if final appears more than once as a modifier for a local variable declaration.

It is a compile-time error if the LocalVariableType is var and any of the following are true:

Example 14.4-1. Local Variables Declared With var

The following code illustrates these rules restricting the use of var:

var a = 1;            // Legal
var b = 2, c = 3.0;   // Illegal: multiple declarators
var d[] = new int[4]; // Illegal: extra bracket pairs
var e;                // Illegal: no initializer
var f = { 6 };        // Illegal: array initializer
var g = (g = 7);      // Illegal: self reference in initializer

These restrictions help to avoid confusion about the type being represented by var.

Sections 14.22-14.29 are left deliberately unused to allow for future language evolution.

14.30 Patterns

A pattern is a construct for declaring local variables more concisely, and in more contexts, than a local variable declaration statement. A pattern appears as an operand of a statement or an expression. The variables in a pattern, known as pattern variables, represent data to be extracted, if possible, from a value provided by the statement or expression.

Pattern matching is the process of determining whether, given a pattern, it is possible to extract data from a given value and, if it is, assigning values to the pattern variables.

The treatment of scoping of pattern variables in 6.3.1 ensures that pattern variables are only in scope where pattern matching is guaranteed to have succeeded and hence the pattern variables will have been assigned a value at run-time. It is not possible to use a pattern variable when it is has not been assigned a value.

14.30.1 Kinds of Patterns

Pattern:
TypeTestPattern
14.30.1.1 Type Test Pattern
TypeTestPattern:
{ PatternVariableModifier } UnannReferenceType Identifier
PatternVariableModifier:
Annotation

See 8.3 for UnannReferenceType.

A type test pattern consists of a type and a pattern variable. It is a compile-time error if the type does not denote a reference type (4.3).

The type of a type test pattern is the UnannReferenceType.

A type test pattern is said to declare the pattern variable Identifier. The scope of that pattern variable Identifier is conditional on the context, as defined in 6.3. The type of the pattern variable Identifier is defined to be UnannReferenceType.

14.30.2 Compatibility of an Expression with a Pattern

An expression, e, is compatible with a type test pattern of type T if the expression e can be converted to type T by a casting conversion (5.5), and the casting conversion does not make use of a narrowing reference conversion which is unchecked (5.1.6.2).

14.30.3 Execution of Pattern Matching

At run time, a value is matched against a pattern. If the value matches the pattern, then additionally values may be assigned to any pattern variables declared in the pattern.

The rules for determining whether a value matches a pattern (or not) and possibly assigning values to pattern variables are as follows:

Chapter 15: Expressions

15.20 Relational Operators

The numerical comparison operators <, >, <=, and >=, and the instanceof operator, are called the relational operators.

RelationalExpression:
ShiftExpression
RelationalExpression < ShiftExpression
RelationalExpression > ShiftExpression
RelationalExpression <= ShiftExpression
RelationalExpression >= ShiftExpression
RelationalExpression instanceof ReferenceType ReferenceTypeOrPattern

Patterns are defined in 14.30.

The relational operators are syntactically left-associative (they group left-to-right).

However, this fact is not useful. For example, a<b<c parses as (a<b)<c, which is always a compile-time error, because the type of a<b is always boolean and < is not an operator on boolean values.

The type of a relational expression is always boolean.

15.20.2 Type Comparison Operator instanceof The instanceof Operator

The type of the RelationalExpression operand of the instanceof operator must be a reference type or the null type, or a compile-time error occurs.

It is a compile-time error if the ReferenceType mentioned after the instanceof operator does not denote a reference type that is reifiable (4.7).

If a cast of the RelationalExpression to the ReferenceType would be rejected as a compile-time error (15.16), then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.

At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast to the ReferenceType without raising a ClassCastException. Otherwise the result is false.

ReferenceTypeOrPattern:
ReferenceType
Pattern

An instanceof operator has one of two forms: (i) a type instanceof operator, where the ReferenceTypeOrPattern operand is a ReferenceType; or (ii) a pattern instanceof operator, where the ReferenceTypeOrPattern operand is a Pattern.

The following applies to a type instanceof operator:

The following applies to a pattern instanceof operator:

Example 15.20.2-1. The type instanceof Operator

class Point   { int x, y; }
class Element { int atomicNumber; }
class Test {
    public static void main(String[] args) {
        Point   p = new Point();
        Element e = new Element();
        if (e instanceof Point) {  // compile-time error
            System.out.println("I get your point!");
            p = (Point)e;  // compile-time error
        }
    }
}

This program results in two compile-time errors. The cast (Point)e is incorrect because no instance of Element or any of its possible subclasses (none are shown here) could possibly be an instance of any subclass of Point. The instanceof expression is incorrect for exactly the same reason. If, on the other hand, the class Point were a subclass of Element (an admittedly strange notion in this example):

class Point extends Element { int x, y; }

then the cast would be possible, though it would require a run-time check, and the instanceof expression would then be sensible and valid. The cast (Point)e would never raise an exception because it would not be executed if the value of e could not correctly be cast to type Point.

Chapter 16: Definite Assignment

Each local variable that is not a pattern variable (14.4) and every blank final field (4.12.4, 8.3.1.2) must have a definitely assigned value when any access of its value occurs.

An access to its value consists of the simple name of the variable (or, for a field, the simple name of the field qualified by this) occurring anywhere in an expression except as the left-hand operand of the simple assignment operator = (15.26.1).

For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs.

Similarly, every blank final variable must be assigned at most once; it must be definitely unassigned when an assignment to it occurs.

Such an assignment is defined to occur if and only if either the simple name of the variable (or, for a field, its simple name qualified by this) occurs on the left hand side of an assignment operator.

For every assignment to a blank final variable, the variable must be definitely unassigned before the assignment, or a compile-time error occurs.

The remainder of this chapter is devoted to a precise explanation of the words "definitely assigned before" and "definitely unassigned before".

The rest of this section continues unchanged.

16.2 Definite Assignment and Statements

16.2.15 try Statements

The rules herein cover the try statement (14.20). Since the try-with-resources statement (14.20.3) is defined by translation to a basic try statement, no special rules need to be provided for it.

These rules apply to every try statement (14.20), whether or not it has a finally block:

If a try statement does not have a finally block, then this rule also applies:

If a try statement does have a finally block, then these rules also apply:

Chapter 17: Threads and Locks

17.4 Memory Model

17.4.1 Shared Variables

Memory that can be shared between threads is called shared memory or heap memory.

All instance fields, static fields, and array elements are stored in heap memory. In this chapter, we use the term variable to refer to both fields and array elements.

Local variables (14.4, 14.14, 14.20.3, 14.30), formal method parameters (8.4.1), and exception handler parameters (14.20) are never shared between threads and are unaffected by the memory model.

Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.