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:
To lift the restriction that pattern variables are implicitly final (4.12.4). This allows pattern variables to be considered as a strict subset of local variables. A number of changes to the specification result from this simplification (primarily in 4.11 and 4.12.3, and also a change to the grammar for patterns in 14.30.1).
To allow pattern variables to be explicitly declared
final
(14.30.1).To unify the grammars of the statements that declare local variables; i.e. the local variable declaration statement (14.4), basic
for
statement (14.14.1), and thetry
-with-resources statement (14.20.3). They all now use the LocalVariableDeclaration non-terminal, rather than ad-hoc variants, and then use non-syntactic restrictions to rule out invalid productions (meaning this is not a change to the set of valid Java programs).To make it a compile-time error for an pattern
instanceof
expression to compare an expression of type S against a pattern of type T, where S is a subtype of T (15.20.2). (Thisinstanceof
expression will always succeed and is then pointless. The opposite case, where a pattern match will always fail, is already a compile-time error.)Renamed 'type test patterns' to the simpler 'type patterns'.
Removed erroneous changes to Section 5.5 (Casting Contexts).
A refactoring of the description of the semantics of the pattern
instanceof
operator (15.20.2 and 14.30.2).Remove the unnecessary section header 14.30.2; its contents go in 14.30.1
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 conditionally initialize local variables. 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:
In declarations:
A type in the
extends
orimplements
clause of a class declaration (8.1.4, 8.1.5, 8.5, 9.5)A type in the
extends
clause of an interface declaration (9.1.3, 8.5, 9.5)The return type of a method (including the type of an element of an annotation type) (8.4.5, 9.4, 9.6.1)
A type in the
throws
clause of a method or constructor (8.4.6, 8.8.5, 9.4)A type in the
extends
clause of a type parameter declaration of a generic class, interface, method, or constructor (8.1.2, 9.1.2, 8.4.4, 8.8.4)The type in a field declaration of a class or interface (including an enum constant) (8.3, 9.3, 8.9.1)
The type in a formal parameter declaration of a method, constructor, or lambda expression (8.4.1, 8.8.1, 9.4, 15.27.1)
The type of the receiver parameter of a method (8.4)
The type in a local variable declaration, enhanced
for
statement, or pattern (14.4,14.14.1,14.14.2,14.20.3,14.30)The type in an exception parameter declaration (14.20)
In expressions:
A type in the explicit type argument list to an explicit constructor invocation statement or class instance creation expression or method invocation expression (8.8.7.1, 15.9, 15.12)
In an unqualified class instance creation expression, as the class type to be instantiated (15.9) or as the direct superclass or direct superinterface of an anonymous class to be instantiated (15.9.5)
The element type in an array creation expression (15.10.1)
The type in the cast operator of a cast expression (15.16)
The type that follows the type
instanceof
relational operator (15.20.2)In a method reference expression (15.13), as the reference type to search for a member method or as the class type or array type to construct.
Also, types are used as:
The element type of an array type in any of the above contexts; and
A non-wildcard type argument, or a bound of a wildcard type argument, of a parameterized type in any of the above contexts.
Finally, there are three special terms in the Java programming language which denote the use of a type:
An unbounded wildcard (4.5.1)
The
...
in the type of a variable arity parameter (8.4.1), to indicate an array typeThe simple name of a type in a constructor declaration (8.8), to indicate the class of the constructed object
...
4.12 Variables
4.12.3 Kinds of Variables
There are eight kinds of variables:
A class variable is a field declared using the keyword
static
within a class declaration (8.3.1.1), or with or without the keywordstatic
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).
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 variablea
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.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.
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.
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.
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.
An exception parameter is created each time an exception is caught by a
catch
clause of atry
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.Local variables are declared by local variable declaration statements (14.4).A local variable is a variable declared by a local variable declaration (14.4), or a pattern (14.30). A local variable declared in a pattern is sometimes called a pattern variable.Whenever the flow of control enters a block (14.2) or
for
statement (14.14), a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block orfor
statement.A local variable declaration statement may contain an expression which initializes the variable. The local variable with an initializing expression is not initialized, however, until the local variable declaration statement that declares it is executed. (The rules of definite assignment (16) prevent the value of a local variable from being used before it has been initialized or otherwise assigned a value.) The local variable effectively ceases to exist when the execution of the block or for statement is complete.
A local variable declared by a local variable declaration is created when the flow of control enters the nearest enclosing block (14.2),
for
statement, ortry
-with-resources statement.A local variable declared by a local variable declaration is initialized as part of the execution of its nearest enclosing statement, provided it has an initializer. The rules of definite assignment (16) prevent the value of a local variable from being used before it has been initialized or otherwise assigned a value.
A local variable declared by a pattern is created and initialized when the pattern matches (14.30.2). The rules of scoping (6.3) prevent the value of a pattern variable from being used unless its declaring type pattern has matched.
A local variable ceases to exist when its declaration is no longer in scope (6.3).
Were it not for one exceptional situation, a local variable declared by a local variable declaration statement could always be regarded as being created when the
its local variable declarationstatement is executed. The exceptional situation involves theswitch
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:
A local variable whose declarator has an initializer (
14.4.214.4) or is declared by a pattern is effectively final if all of the following are true:It is not declared
final
.It never occurs as the left hand side in an assignment expression (15.26). (Note that the local variable declarator containing the initializer is not an assignment expression.)
It never occurs as the operand of a prefix or postfix increment or decrement operator (15.14, 15.15).
A local variable declared by a local variable declaration whose declarator lacks an initializer is effectively final if all of the following are true:
It is not declared
final
.Whenever it occurs as the left hand side in an assignment expression, it is definitely unassigned and not definitely assigned before the assignment; that is, it is definitely unassigned and not definitely assigned after the right hand side of the assignment expression (16).
It never occurs as the operand of a prefix or postfix increment or decrement operator.
A method, constructor, lambda, or exception parameter (8.4.1, 8.8.1, 9.4, 15.27.1, 14.20) is treated, for the purpose of determining whether it is effectively final, as a local variable whose declarator has an initializer.
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:
Each class variable, instance variable, or array component is initialized with a default value when it is created (15.9, 15.10.2):
For type
byte
, the default value is zero, that is, the value of(byte)0
.For type
short
, the default value is zero, that is, the value of(short)0
.For type
int
, the default value is zero, that is,0
.For type
long
, the default value is zero, that is,0L
.For type
float
, the default value is positive zero, that is,0.0f
.For type
double
, the default value is positive zero, that is,0.0d
.For type
char
, the default value is the null character, that is,'\u0000'
.For type
boolean
, the default value isfalse
.For all reference types (4.3), the default value is
null
.
Each method parameter (8.4.1) is initialized to the corresponding argument value provided by the invoker of the method (15.12).
Each constructor parameter (8.8.1) is initialized to the corresponding argument value provided by a class instance creation expression (15.9) or explicit constructor invocation (8.8.7).
An exception parameter (14.20) is initialized to the thrown object representing the exception (11.3, 14.18).
A local variable declared by a local variable declaration (14.4
, 14.14) must be explicitly given a value before it is used, by either initialization(14.4), or assignment (15.26),in a way that can be verified using the rules for definite assignment (16). A pattern variable is initialized by the process of pattern matching (14.30.2).
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 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:
A module, declared in a
module
declaration (7.7)A package, declared in a
package
declaration (7.4)An imported type, declared in a single-type-import declaration or a type-import-on-demand declaration (7.5.1, 7.5.2)
An imported
static
member, declared in a single-static-import declaration or a static-import-on-demand declaration (7.5.3, 7.5.4)A class, declared in a class type declaration (8.1)
An interface, declared in an interface type declaration (9.1)
A type parameter, declared as part of the declaration of a generic class, interface, method, or constructor (8.1.2, 9.1.2, 8.4.4, 8.8.4)
A member of a reference type (8.2, 9.2, 8.9.3, 9.6, 10.7), one of the following:
An enum constant (8.9)
A field, one of the following:
A method, one of the following:
A parameter, one of the following:
A formal parameter of a method or constructor of a class type or enum type (8.4.1, 8.8.1, 8.9.2), or of a lambda expression (15.27.1)
A formal parameter of an
abstract
method of an interface type or annotation type (9.4, 9.6.1)An exception parameter of an exception handler declared in a
catch
clause of atry
statement (14.20)
A local variable, 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), including the local variable declaration implicitly provided by an enhanced for
statement (14.4.2), 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:
Its own initializer
Any further declarators to the right in the ForInit part of the
for
statementThe Expression and ForUpdate parts of the
for
statementThe contained Statement
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 local 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.
The scope of a local variable declared by a pattern is defined below.
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
The scope of a pattern variable, a local variable declared by a pattern, is the part of the program that might be executed after pattern matching of a value against the pattern has succeeded (14.30.2).
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 program points where it is definitely matched in a region beginning with the pattern that declares the pattern variable.
The remainder of this section is devoted to a precise explanation of the words "definitely matched", for which we define three auxiliary technical terms:
- a pattern variable is introduced by an expression when true;
- a pattern variable is introduced by an expression when false; and
- a pattern variable is introduced by a statement.
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 expressiona instanceof String s
when true. In other words, if the value of the expression istrue
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 isfalse
.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):
- V is introduced by
a && b
when true iff either- V is introduced by
a
when true, or - V is introduced by
b
when true.
a
when true, and V is introduced byb
when true. - V is introduced by
A pattern variable introduced by
a
when true is definitely matched atb
.It is a compile-time error if any pattern variable introduced by
a
when true is already in scope atb
.
The first rule excludes the possibility of declaring a pattern variable in the scope of another declaration of a pattern variable of the same name.
if ((a instanceof String s) && (b instanceof String s)) { // Error! System.out.println(s); }
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
.
- It is a compile-time error if a pattern variable is both introduced by
a
when false, and byb
when false.
6.3.1.2 Conditional-Or Operator ||
The following rules apply to a conditional-or expression (15.24):
V is introduced by
a || b
when false iff either- V is introduced by
a
when false, or - V is introduced by
b
when false.
It is a compile-time error if both V is introduced by
a
when false, and V is introduced byb
when false.- V is introduced by
A pattern variable introduced by
a
when false is definitely matched atb
.It is a compile-time error if any pattern variable introduced by
a
when false is already in scope atb
.
It is a compile-time error if a pattern variable is both introduced by
a
when true, and byb
when true.This final case rules out an example such as the following:
if ((a instanceof String t) || (b instanceof String t)) { System.out.println(t); // Error! }
As it stands the pattern variable
t
is not in scope in the first contained statement, but this may be relaxed in future versions of the language.
6.3.1.3 Logical Complement Operator !
The following rules apply to a logical complement expression (15.15.6):
V is introduced by
!a
when true iff V is introduced bya
when false.V is introduced by
!a
when false iff V is introduced bya
when true.
6.3.1.4 Conditional Operator ? :
The following rules apply to a conditional expression a ? b : c
(15.25):
A pattern variable introduced by
a
when true is definitely matched atb
.It is a compile-time error if any pattern variable introduced by
a
when true is already in scope atb
.A pattern variable introduced by
a
when false is definitely matched atc
.It is a compile-time error if any pattern variable introduced by
a
when false is already in scope atc
.It is a compile-time error if any of the following conditions hold:
A pattern variable is introduced both by
a
when true, and byc
when true.A pattern variable is introduced both by
a
when false, and byb
when true.A pattern variable is introduced both by
b
when true, and byc
when true.A pattern variable is introduced both by
a
when true, and byc
when false.A pattern variable is introduced both by
a
when false, and byb
when false.A pattern variable is introduced both by
b
when false, and byc
when false.
These final cases are to rule out cases of the introduction of pattern variables that may be supported in future versions of the language.
6.3.1.5 instanceof
Operator
The following rule applies to an instanceof
expression (15.20.2):
V is introduced by
a instanceof p
when true iff V is declared by patternp
. (The rules for determining which pattern variables are declared by a pattern are given in 14.30.1.)It is a compile-time error if any pattern variable introduced by the pattern
p
is already in scope at theinstanceof
expression.
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).
- A pattern variable introduced by a statement S contained in a switch labeled statement group (14.11.1) is definitely matched at all the statements following S, if any, in the switch labeled statement group.
6.3.1.7 Parenthesized Expressions
The following rules cover the parenthesized expression (15.8.5).
A pattern variable is introduced by
(a)
when true if and only if it is introduced bya
when true.A pattern variable is introduced by
(a)
when false if and only if it is introduced bya
when false.
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 expressions contained within if
, while
, do
, and for
statements can, in certain circumstances, include other contained statements. Here is an example:
if (x instanceof String s)
// String s in scope for this contained statement
// No explicit cast needed here!
System.out.println("The string value was: " + s);
else
// String s not in scope for this contained statement
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:
- A pattern variable introduced by S is definitely matched at all the block statements following S, if any, in the block.
6.3.2.2 if
Statements
The following rules apply to a statement if (e) S
(14.9.1):
A pattern variable introduced by
e
when true is definitely matched atS
.It is a compile-time error if any pattern variable introduced by
e
when true is already in scope atS
.V is introduced by
if (e) S
iff V is introduced bye
when false andS
cannot complete normally.It is a compile-time error if any pattern variable introduced by the
if
statement is already in scope.
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):
A pattern variable introduced by
e
when true is definitely matched atS
.It is a compile-time error if any pattern variable introduced by
e
when true is already in scope atS
.A pattern variable introduced by
e
when false is definitely matched atT
.It is a compile-time error if any pattern variable introduced by
e
when false is already in scope atT
.V is introduced by
if (e) S else T
iff either:- V is introduced by
e
when true,S
can complete normally, andT
cannot complete normally; or - V is introduced by
e
when false,S
cannot complete normally, andT
can complete normally.
It is a compile-time error if any pattern variable introduced by the
if
statement is already in scope.- V is introduced by
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 theinstanceof
operator and is in scope in the first contained statement (the one before theelse
keyword), but it is not in scope in the second contained statement (the one after theelse
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):
A pattern variable introduced by
e
when true is definitely matched atS
.It is a compile-time error if any pattern variable introduced by
e
when true is already in scope atS
.V is introduced by
while (e) S
iff V is introduced bye
when false, and S does not contains a reachablebreak
statement whose break target contains S.It is a compile-time error if any pattern variable introduced by the
while
statement is already in scope.
6.3.2.4 do
Statements
The following rule applies to a statement do S while (e)
(14.13):
V is introduced by
do S while (e)
iff V is introduced bye
when false, andS
does not contain a reachablebreak
statement whose break target containsS
.It is a compile-time error if any pattern variable introduced by the
do
statement is already in scope.
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.
A pattern variable introduced by the condition expression when true is definitely matched at both the incrementation part and the contained statement.
It is a compile-time error if any pattern variable introduced by the condition expression is already in scope at the incrementation part or the contained statement.
V is introduced by a
for
statement iff V is introduced by the condition expression when false, and the contained statement, S, does not contain a reachablebreak
statement whose break target contains S.It is a compile-time error if any pattern variable introduced by a
for
statement is already in scope.
6.3.2.6 switch
Statements
The following rule covers the switch
statement (14.11).
- A pattern variable is introduced by a labeled statement S contained in a switch block statement group (14.11) is definitely matched at all the statements following S, if any, in the switch block statement group.
6.3.2.7 Labeled Statements
The following rule covers the labeled statement (14.7).
- A pattern variable is introduced by a labeled statement if and only if it is introduced by its immediately contained Statement.
6.4 Shadowing and Obscuring
A local variable (14.4, 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 patterns often employ the same 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){ // Error
System.out.print("b is a point (" + p.x + ", " + p.y);
}
}
System.out.println();
}
}
Pattern variables are not allowed to shadow other 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) // Error
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:
In a
requires
directive in a module declaration (7.7.1)To the right of
to
in anexports
oropens
directive in a module declaration (7.7.2)
A name is syntactically classified as a PackageName in these contexts:
To the right of
exports
oropens
in a module declarationTo the left of the "
.
" in a qualified PackageName
A name is syntactically classified as a TypeName in these contexts:
The first eleven non-generic contexts (6.1):
In a
uses
orprovides
directive in a module declaration (7.7.1)In a single-type-import declaration (7.5.1)
To the left of the
.
in a single-static-import declaration (7.5.3)To the left of the
.
in a static-import-on-demand declaration (7.5.4)To the left of the
(
in a constructor declaration (8.8)After the
@
sign in an annotation (9.7)To the left of
.class
in a class literal (15.8.2)To the left of
.this
in a qualifiedthis
expression (15.8.4)To the left of
.super
in a qualified superclass field access expression (15.11.2)To the left of
.
Identifier or.super.
Identifier in a qualified method invocation expression (15.12)To the left of
.super::
in a method reference expression (15.13)
As the Identifier or dotted Identifier sequence that constitutes any ReferenceType (including a ReferenceType to the left of the brackets in an array type, or to the left of the < in a parameterized type, or in a non-wildcard type argument of a parameterized type, or in an
extends
orsuper
clause of a wildcard type argument of a parameterized type) in the 16 contexts where types are used (4.11):In an
extends
orimplements
clause of a class declaration (8.1.4, 8.1.5, 8.5, 9.5)In an
extends
clause of an interface declaration (9.1.3)The return type of a method (8.4, 9.4) (including the type of an element of an annotation type (9.6.1))
In the
throws
clause of a method or constructor (8.4.6, 8.8.5, 9.4)In an
extends
clause of a type parameter declaration of a generic class, interface, method, or constructor (8.1.2, 9.1.2, 8.4.4, 8.8.4)The type in a field declaration of a class or interface (8.3, 9.3)
The type in a formal parameter declaration of a method, constructor, or lambda expression (8.4.1, 8.8.1, 9.4, 15.27.1)
The type of the receiver parameter of a method (8.4)
The type in a local variable declaration, enhanced
for
statement header, or pattern (14.4,14.14.1,14.14.2,14.20.314.30)A type in an exception parameter declaration (14.20)
In an explicit type argument list to an explicit constructor invocation statement or class instance creation expression or method invocation expression (8.8.7.1, 15.9, 15.12)
In an unqualified class instance creation expression, either as the class type to be instantiated (15.9) or as the direct superclass or direct superinterface of an anonymous class to be instantiated (15.9.5)
The element type in an array creation expression (15.10.1)
The type in the cast operator of a cast expression (15.16)
The type that follows the
instanceof
relational operator (15.20.2)In a method reference expression (15.13), as the reference type to search for a member method or as the class type or array type to construct.
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 termp.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 ofp
,q
, andFoo
is a type name or a package name.As another example, suppose a cast operator uses the type
p.q.Foo<? extends String>
. The termp.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 termString
is extracted as an Identifier in anextends
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:
As the qualifying expression in a qualified superclass constructor invocation (8.8.7.1)
As the qualifying expression in a qualified class instance creation expression (15.9)
As the array reference expression in an array access expression (15.10.3)
As a PostfixExpression (15.14)
As the left-hand operand of an assignment operator (15.26)
As a VariableAccess in a
try
-with-resources statement (14.20.3)
A name is syntactically classified as a MethodName in this context:
- Before the "
(
" in a method invocation expression (15.12)
A name is syntactically classified as a PackageOrTypeName in these contexts:
To the left of the "
.
" in a qualified TypeNameIn a type-import-on-demand declaration (7.5.2)
A name is syntactically classified as an AmbiguousName in these contexts:
To the left of the "
.
" in a qualified ExpressionNameTo the left of the rightmost
.
that occurs before the "(
" in a method invocation expressionTo the left of the "
.
" in a qualified AmbiguousNameIn the default value clause of an annotation type element declaration (9.6.2)
To the right of an "
=
" in an an element-value pair (9.7.1)To the left of
::
in a method reference expression (15.13)
The effect of syntactic classification is to restrict certain kinds of entities to certain parts of expressions:
The name of a field, parameter, or local variable may be used as an expression (15.14.1).
The name of a method may appear in an expression only as part of a method invocation expression (15.12).
The name of a class or interface type may appear in an expression only as part of a class literal (15.8.2), a qualified
this
expression (15.8.4), a class instance creation expression (15.9), an array creation expression (15.10.1), a cast expression (15.16), aninstanceof
expression (15.20.2), an enum constant (8.9), or as part of a qualified name for a field or method.The name of a package may appear in an expression only as part of a qualified name for a class or interface type.
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:
If the Identifier appears within the scope (6.3) of a local variable declaration (14.4, 14.14, 14.20.3, 14.30) or parameter declaration (8.4.1, 8.8.1, 14.20) or field declaration (8.3) with that name, then the AmbiguousName is reclassified as an ExpressionName.
Otherwise, if a field of that name is declared in the compilation unit (7.3) containing the Identifier by a single-static-import declaration (7.5.3), or by a static-import-on-demand declaration (7.5.4) then the AmbiguousName is reclassified as an ExpressionName.
Otherwise, if the Identifier is a valid TypeIdentifier and appears within the scope (6.3) of a top level class (8) or interface type declaration (9), a local class declaration (14.3) or member type declaration (8.5, 9.5) with that name, then the AmbiguousName is reclassified as a TypeName.
Otherwise, if the Identifier is a valid TypeIdentifier and a type of that name is declared in the compilation unit (7.3) containing the Identifier, either by a single-type-import declaration (7.5.1), or by a type-import-on-demand declaration (7.5.2), or by a single-static-import declaration (7.5.3), or by a static-import-on-demand declaration (7.5.4), then the AmbiguousName is reclassified as a TypeName.
Otherwise, the AmbiguousName is reclassified as a PackageName. A later step determines whether or not a package of that name actually exists.
...
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
:
Module declarations (7.7)
Corresponds to
java.lang.annotation.ElementType.MODULE
Package declarations (7.4.1)
Corresponds to
java.lang.annotation.ElementType.PACKAGE
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
Method declarations (including elements of annotation types) (8.4.3, 9.4, 9.6.1)
Corresponds to
java.lang.annotation.ElementType.METHOD
Constructor declarations (8.8.3)
Corresponds to
java.lang.annotation.ElementType.CONSTRUCTOR
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
Field declarations (including enum constants) (8.3.1, 9.3, 8.9.1)
Corresponds to
java.lang.annotation.ElementType.FIELD
Formal and exception parameter declarations (8.4.1, 9.4, 14.20)
Corresponds to
java.lang.annotation.ElementType.PARAMETER
Local variable declarations (including loop variables of enhanced
for
statementsand resource variables of) and patterns (14.4,try
-with-resources statements14.14.1,14.14.2,14.20.314.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 onf
ifFoo
is meta-annotated by@Target(ElementType.FIELD)
, and a type annotation onint
ifFoo
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
, andC
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 typeint[][]
,@B
applies to its component typeint[]
, and@C
applies to the element typeint
. 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 typeint
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:
Method declarations (including elements of annotation types)
Constructor declarations
Field declarations (including enum constants)
Formal and exception parameter declarations
Local variable declarations (including loop variables of enhanced
for
statementsand resource variables of) and patternstry
-with-resources statements
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:
If the annotation's type is applicable in the declaration context corresponding to the declaration, and not in type contexts, then the annotation is deemed to apply only to the declaration.
If the annotation's type is applicable in type contexts, and not in the declaration context corresponding to the declaration, then the annotation is deemed to apply only to the type which is closest to the annotation.
If the annotation's type is applicable in the declaration context corresponding to the declaration and in type contexts, then the annotation is deemed to apply to both the declaration and the type which is closest to the annotation.
In the second and third cases above, the type which is closest to the annotation is determined as follows:
If the annotation appears before a
void
method declaration or a local variable declaration that usesvar
(14.4, 14.14.2, 14.20.3), then there is no closest type. If the annotation's type is deemed to apply only to the type which is closest to the annotation, a compile-time error occurs.If the annotation appears before a constructor declaration, then the closest type is the type of the newly constructed object. The type of the newly constructed object is the fully qualified name of the type immediately enclosing the constructor declaration. Within that fully qualified name, the annotation applies to the simple type name indicated by the constructor declaration.
In all other cases, the closest type is the type written in source code for the declared entity; if that type is an array type, then the element type is deemed to be closest to the annotation.
For example, in the field declaration
@Foo public static String f;
, the type which is closest to@Foo
isString
. (If the type of the field declaration had been written asjava.lang.String
, thenjava.lang.String
would be the type closest to@Foo
, and later rules would prohibit a type annotation from applying to the package namejava
.) In the generic method declaration@Foo <T> int[] m() {...}
, the type written for the declared entity isint[]
, so@Foo
applies to the element typeint
.Local variable declarations which do not use
var
are similar to formal parameter declarations of lambda expressions, in that both allow declaration annotations and type annotations in source code, but only the type annotations can be stored in theclass
file.
It is a compile-time error if an annotation of type T is syntactically a modifier for:
a module declaration, but T is not applicable to module declarations.
a package declaration, but T is not applicable to package declarations.
a class, interface, or enum declaration, but T is not applicable to type declarations or type contexts; or an annotation type declaration, but T is not applicable to annotation type declarations or type declarations or type contexts.
a method declaration (including an element of an annotation type), but T is not applicable to method declarations or type contexts.
a constructor declaration, but T is not applicable to constructor declarations or type contexts.
a type parameter declaration of a generic class, interface, method, or constructor, but T is not applicable to type parameter declarations or type contexts.
a field declaration (including an enum constant), but T is not applicable to field declarations or type contexts.
a formal or exception parameter declaration, but T is not applicable to either formal and exception parameter declarations or type contexts.
a receiver parameter, but T is not applicable to type contexts.
a local variable declaration (including a loop variable of
aan enhancedfor
statementor a resource variable of a) or a type pattern, but T is not applicable to local variable declarations or type contexts.try
-with-resources statement
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 simple name to which the annotation is closest is classified as a TypeName, not a PackageName.
If the simple name to which the annotation is closest is followed by "
.
" and another TypeName - that is, the annotation appears as@Foo T.U
- thenU
denotes an inner class ofT
.
The intuition behind the second clause is that if
Outer.this
is legal in a nested class enclosed byOuter
, thenOuter
may be annotated because it represents the type of some object at run time. On the other hand, ifOuter.this
is not legal - because the class where it appears has no enclosing instance ofOuter
at run time - thenOuter
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 ofB
, asB
has no lexically enclosing instances (8.5.1). Therefore, it is not possible to apply@Foo
toA
in the typeA.B
, becauseA
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 ofD
. Therefore, it is possible to apply@Foo
toC
in the typeC.D
, becauseC
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
andjava.@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 off
(and not to the typejava.lang.Object
) becauseTA
is applicable in the field declaration context.
Chapter 14: Blocks and Statements and Patterns
14.4 Local Variable Declaration Statements Declarations
A local variable declaration statement declares one or more local variable names.
- LocalVariableDeclarationStatement:
- LocalVariableDeclaration
;
A local variable declaration declares one or more local variables.
- 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 declaration may appear in the header of a basic for
statement (14.14.1), an enhanced or as a resource in a for
statement (14.14.2),try
-with-resources statement (14.20.3). An enhanced for
statement (14.14.2) implicitly provides a local variable declaration statement.
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:
More than one VariableDeclarator is listed.
The VariableDeclaratorId has one or more bracket pairs.
The VariableDeclarator lacks an initializer.
The initializer of the VariableDeclarator is an ArrayInitializer.
The initializer of the VariableDeclarator contains a reference to the variable.
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
.
14.4.1 Local Variable Declarators and Types
Each declarator in a local variable declaration declares one local variable, whose name is the Identifier that appears in the declarator.
If the optional keyword final
appears at the start of the declaration, the variable being declared is a final variable (4.12.4).
The declared type of a local variable is determined as follows:
If LocalVariableType is an UnannType, and no bracket pairs appear in UnannType or VariableDeclaratorId, then UnannType denotes the type of the local variable.
If LocalVariableType is an UnannType, and bracket pairs appear in UnannType or VariableDeclaratorId, then the type of the local variable is specified by 10.2.
If LocalVariableType is
var
, then let T be the type of the initializer expression when treated as if it did not appear in an assignment context, and were thus a standalone expression (15.2). The type of the local variable is the upward projection of T with respect to all synthetic type variables mentioned by T (4.10.5).It is a compile-time error if T is the null type.
Because the initializer is treated as if it did not appear in an assignment context, an error occurs if it is a lambda expression (15.27) or a method reference expression (15.13).
Example 14.4.1-1. Type of Local Variables Declared With var
The following code illustrates the typing of variables declared with var
:
var a = 1; // a has type 'int'
var b = java.util.List.of(1, 2); // b has type 'List<Integer>'
var c = "x".getClass(); // c has type 'Class<? extends String>'
// (see JLS 15.12.2.6)
var d = new Object() {}; // d has the type of the anonymous class
var e = (CharSequence & Comparable<String>) "x";
// e has type CharSequence & Comparable<String>
var f = () -> "hello"; // Illegal: lambda not in an assignment context
var g = null; // Illegal: null type
Note that some variables declared with var
cannot be declared with an explicit type, because the type of the variable is not denotable.
Upward projection is applied to the type of the initializer when determining the type of the variable. If the type of the initializer contains capture variables, this projection maps the type of the initializer to a supertype that does not contain capture variables.
While it would be possible to allow the type of the variable to mention capture variables, by projecting them away we enforce an attractive invariant that the scope of a capture variable is never larger than the statement containing the expression whose type is captured. Informally, capture variables cannot "leak" into subsequent statements.
A local variable of type float
always contains a value that is an element of the float value set (4.2.3); similarly, a local variable of type double
always contains a value that is an element of the double value set. It is not permitted for a local variable of type float
to contain an element of the float-extended-exponent value set that is not also an element of the float value set, nor for a local variable of type double
to contain an element of the double-extended-exponent value set that is not also an element of the double value set.
The scope and shadowing of a local variable declaration is specified in 6.3 and 6.4.
14.4.2 Execution of Local Variable Declarations Local Variable Declaration Statements
A local variable declaration statement consists of a local variable declaration, which can declare and optionally initialize one or more local variables (4.12.3).
- LocalVariableDeclarationStatement:
- LocalVariableDeclaration
;
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.
A local variable declaration statement is an executable statement. (Thus it is local variable declaration statements, not local variable declarations, that are executed.) Every time it is executed, the declarators are processed in order from left to right. If a declarator has an initializer, the initializer is evaluated and its value is assigned to the variable.
If a declarator does not have an initializer, then every reference to the variable must be preceded by execution of an assignment to the variable, or a compile-time error occurs by the rules of 16.
Each initializer (except the first) is evaluated only if evaluation of the preceding initializer completes normally.
Execution of the local variable declaration completes normally only if evaluation of the last initializer completes normally.
If the local variable declaration contains no initializers, then executing it always completes normally.
14.14 The for
Statement
14.14.2 The enhanced for
statement
The enhanced for
statement has the form:
- EnhancedForStatement:
for
(
{VariableModifier} LocalVariableType VariableDeclaratorId:
Expression)
Statement- EnhancedForStatementNoShortIf:
for
(
{VariableModifier} LocalVariableType VariableDeclaratorId:
Expression)
StatementNoShortIf
The following productions from 4.3, 8.3, 8.4.1, and 14.4 are shown here for convenience:
- VariableModifier:
- Annotation
final
- LocalVariableType:
- UnannType
var
- VariableDeclaratorId:
- Identifier [Dims]
- Dims:
- {Annotation}
[
]
{{Annotation}[
]
}
The header of the enhanced for
statement declares a local variable, whose name is the identifier given by VariableDeclaratorId provides a name, type, and modifiers used to implicitly declare a local variable in the body of the enhanced for
statement.
If the keyword final
appears at the start of the declaration, the variable being declared is a final
variable (4.12.4).
It is a compile-time error if the LocalVariableType is var
and the VariableDeclaratorId has one or more bracket pairs.
The type of the Expression must be a subtype of the raw type Iterable
or an array type (10.1), or a compile-time error occurs.
The type of the local variable is determined as follows:
If LocalVariableType is an UnannType, and no bracket pairs appear in UnannType or VariableDeclaratorId, then UnannType denotes the type of the local variable.
If LocalVariableType is an UnannType, and bracket pairs appear in UnannType or VariableDeclaratorId, then the type of the local variable is specified by 10.2.
If LocalVariableType is
var
, then let T be derived from the type of the Expression, as follows:If the Expression has an array type, then T is the component type of the array type.
Otherwise, if the Expression has a type that is a subtype of
Iterable<
X>
, for some type X, then T is X.Otherwise, the Expression has a type that is a subtype of the raw type
Iterable
, and T isObject
.
The type of the local variable is the upward projection of T with respect to all synthetic type variables mentioned by T (4.10.5).
The scope and shadowing of the local variable is specified in 6.3 and 6.4.
When an enhanced for
statement is executed, the local variable is initialized, on each iteration of the loop, to successive elements of the array or Iterable
produced by the expression. The precise meaning of the enhanced for
statement is given by translation into a basic for
statement, as follows:
If the type of Expression is a subtype of
Iterable
, then the translation is as follows.If the type of Expression is a subtype of
Iterable<
X>
for some type argument X, then let I be the typejava.util.Iterator<
X>
; otherwise, let I be the raw typejava.util.Iterator
.The enhanced
for
statement is equivalent to a basicfor
statement of the form:for (*I* #i = *Expression*.iterator(); #i.hasNext(); ) { *{VariableModifier} TargetType Identifier* = (*TargetType*) #i.next(); *Statement* }
#i
is an automatically generated identifier that is distinct from any other identifiers (automatically generated or otherwise) that are in scope (6.3) at the point where the enhancedfor
statement occurs.If the declared type of the local variable in the header of the enhanced
for
statement is a reference type, then TargetType is that declared type; otherwise, TargetType is the upper bound of the capture conversion (5.1.10) of the type argument of I, orObject
if I is raw.For example, this code:
List<? extends Integer> l = ... for (float i : l) ...
will be translated to:
for (Iterator<Integer> #i = l.iterator(); #i.hasNext(); ) { float #i0 = (Integer)#i.next(); ...
Otherwise, the Expression necessarily has an array type, T
[]
.Let L1 ... Lm be the (possibly empty) sequence of labels immediately preceding the enhanced
for
statement.The enhanced
for
statement is equivalent to a basicfor
statement of the form:*T*`[]` #a = *Expression*; *L~1~*: *L~2~*: ... *L~m~*: for (int #i = 0; #i < #a.length; #i++) { *{VariableModifier} TargetType Identifier* = #a[#i]; *Statement* }
#a
and#i
are automatically generated identifiers that are distinct from any other identifiers (automatically generated or otherwise) that are in scope at the point where the enhancedfor
statement occurs.TargetType is the declared type of the local variable in the header of the enhanced
for
statement.
Example 14.14-1. Enhanced for
And Arrays
The following program, which calculates the sum of an integer array, shows how enhanced for
works for arrays:
int sum(int[] a) {
int sum = 0;
for (int i : a) sum += i;
return sum;
}
Example 14.14-2. Enhanced for
And Unboxing Conversion
The following program combines the enhanced for
statement with auto-unboxing to translate a histogram into a frequency table:
Map<String, Integer> histogram = ...;
double total = 0;
for (int i : histogram.values())
total += i;
for (Map.Entry<String, Integer> e : histogram.entrySet())
System.out.println(e.getKey() + " " + e.getValue() / total);
}
14.20 The try
statement
14.20.3 try
-with-resources
A try
-with-resources statement is parameterized with local variables (known as resources) that are initialized before execution of the try
block and closed automatically, in the reverse order from which they were initialized, after execution of the try
block. catch
clauses and a finally
clause are often unnecessary when resources are closed automatically.
- TryWithResourcesStatement:
try
ResourceSpecification Block [Catches] [Finally]- ResourceSpecification:
(
ResourceList [;
])
- ResourceList:
- Resource {
;
Resource} - Resource:
{VariableModifier} LocalVariableType IdentifierLocalVariableDeclaration=
Expression- VariableAccess
- VariableAccess:
- ExpressionName
- FieldAccess
The following productions from 4.3, 8.3, 8.4.1 and 14.4 are shown here for convenience:
- VariableModifier:
- Annotation
final
- LocalVariableType:
- UnannType
var
- LocalVariableDeclaration:
- {VariableModifier} LocalVariableType VariableDeclaratorList
- LocalVariableType:
- UnannType
var
- VariableModifier:
- Annotation
final
- VariableDeclaratorList:
- VariableDeclarator {
,
VariableDeclarator}- VariableDeclarator:
- VariableDeclaratorId [
=
VariableInitializer]- VariableDeclaratorId:
- Identifier [Dims]
- Dims:
- {Annotation}
[
]
{{Annotation}[
]
}
A resource specification uses variables to denote resources for the try
statement, either by declaring local variables with initializer expressions or by referring to suitable existing variables. An existing variable is referred to by either an expression name (6.5.6) or a field access expression (15.11).
Any local variable declaration (14.4) appearing in the resource specification is a restricted form of a local variable declaration; the following must all be true, otherwise a compile-time error occurs:
The VariableDeclaratorList consists of a single VariableDeclarator.
The VariableDeclarator has an initializer.
The VariableDeclaratorId has no bracket pairs.
It is a compile-time error for a resource specification to declare two variables with the same name.
It is a compile-time error if final
appears more than once as a modifier for each variable declared in a resource specification.
A variable declared in a resource specification is implicitly declared final
if it is not explicitly declared final
(4.12.4).
A resource denoted by an expression name or field access expression must be a final
or effectively final
variable that is definitely assigned before the try
-with-resources statement (16), or a compile-time error occurs.
It is a compile-time error if the LocalVariableType of a variable declared in a resource specification is var
and the initializer expression contains a reference to the variable.
The type of a variable declared in a resource specification is determined as follows:
If LocalVariableType is an UnannType, then UnannType denotes the type of the local variable.
If LocalVariableType is
var
, then let T be the type of the initializer expression when treated as if it did not appear in an assignment context, and were thus a standalone expression (15.2). The type of the local variable is the upward projection of T with respect to all synthetic type variables mentioned by T (4.10.5).It is a compile-time error if T is the null type.
The type of a variable declared or referred to as a resource in a resource specification must be a subtype of AutoCloseable
, or a compile-time error occurs.
The scope and shadowing of a variable declared in a resource specification is specified in 6.3 and 6.4.
Resources are initialized in left-to-right order. If a resource fails to initialize (that is, its initializer expression throws an exception), then all resources initialized so far by the try
-with-resources statement are closed. If all resources initialize successfully, the try
block executes as normal and then all non-null resources of the try
-with-resources statement are closed.
Resources are closed in the reverse order from that in which they were initialized. A resource is closed only if it initialized to a non-null value. An exception from the closing of one resource does not prevent the closing of other resources. Such an exception is suppressed if an exception was thrown previously by an initializer, the try
block, or the closing of a resource.
A try
-with-resources statement whose resource specification indicates multiple resources is treated as if it were multiple try
-with-resources statements, each of which has a resource specification that indicates a single resource. When a try
-with-resources statement with n resources (n > 1) is translated, the result is a try
-with-resources statement with n-1 resources. After n such translations, there are n nested try
-catch
-finally
statements, and the overall translation is complete.
Sections 14.22-14.29 are left deliberately unused to allow for future language evolution.
14.30 Patterns
A pattern describes a test that can be performed on a value. Patterns appear as an operand of a statement or an expression, which provides the value to be tested. A pattern also declares local variables, known as pattern variables.
The process of testing a value against a pattern is known as pattern matching. If a value successfully matches a pattern, the process of pattern matching also assigns values to the pattern variables declared by the pattern; otherwise the value is said to have not matched the pattern.
The rules of scoping (6.3) ensure that pattern variables are only in scope where pattern matching has definitely succeeded and the pattern variables will have been assigned a value. It is not possible to use a pattern variable where it has not been assigned a value.
14.30.1 Kinds of Patterns
A type pattern declares a pattern variable and is used to test whether a value is an instance of the type appearing in the pattern.
- Pattern:
- TypePattern
- TypePattern:
- {VariableModifier} UnannType Identifier
The following production from 8.4.1 is shown here for convenience:
- VariableModifier:
- Annotation
final
The type of a type pattern is the type denoted by UnannType. It is a compile-time error if UnannType is not a reference type.
The pattern variable declared by a type pattern has the name Identifier and the type denoted by UnannType.
An expression, e, is compatible with a 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.2 Pattern Matching
Pattern matching is the process of testing a value against a pattern. If a value successfully matches a pattern, pattern matching also assigns values to the pattern variables declared by the pattern.
The rules for determining whether a value successfully matches a pattern (or not) and assigning values to pattern variables are as follows:
- A value, V, that is not the null reference matches a type pattern of type T if V can be cast to T without raising a
ClassCastException
, in which case the value V is assigned to the pattern variable declared by the pattern; and it does not match otherwise.
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
ReferenceTypeReferenceTypeOrPattern
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 ofa<b
is alwaysboolean
and < is not an operator onboolean
values.
The type of a relational expression is always boolean
.
15.20.2 Type Comparison Operator instanceof
The instanceof
Operator
instanceof
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 (14.30).
The following apply to a type instanceof
operator:
The type of the RelationalExpression operand of the type
instanceof
operator must be a reference type or the null type, or a compile-time error occurs.The expression RelationalExpression is compatible with the type ReferenceType if (i) RelationalExpression can be converted to type ReferenceType by casting conversion (5.5), and (ii) the casting conversion does not make use of a narrowing reference conversion which is unchecked (5.1.6.2). If RelationalExpression is not compatible with ReferenceType then a compile-time error occurs.
At run time, the result of the
instanceof
operator istrue
if the value of the RelationalExpression is not the null reference and the reference could be cast to the ReferenceType without raising aClassCastException
. Otherwise the result isfalse
.
The following apply to a pattern instanceof
operator:
The type of the RelationalExpression operand of the pattern
instanceof
operator must be a reference type or the null type, or a compile-time error occurs.The RelationalExpression operand of a pattern
instanceof
operator must be compatible with the Pattern operand as defined in 14.30.1; otherwise, a compile-time error occurs.If the type of the RelationalExpression is a subtype of the type of the Pattern then a compile-time error occurs.
At run time, the result of the
instanceof
operator is determined as follows:If the value of the RelationalExpression is the null reference, then the result is
false
.If the value of the RelationalExpression is not the null reference, then it is matched against the Pattern, as detailed in 14.30.2 (which may result in pattern variables being assigned values). If it matches then the result of the pattern
instanceof
operator istrue
, otherwise the result of the patterninstanceof
operator isfalse
.
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 declared by a local variable declaration (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.
The text above was missing from previous editions of the JLS.
These rules apply to every try
statement (14.20), whether or not it has a finally
block:
V is [un]assigned before the
try
block iff V is [un]assigned before thetry
statement.V is definitely assigned before a
catch
block iff V is definitely assigned before thetry
block.V is definitely unassigned before a
catch
block iff all of the following are true:V is definitely unassigned after the
try
block.V is definitely unassigned before every
return
statement that belongs to thetry
block.V is definitely unassigned after e in every statement of the form
throw
e that belongs to thetry
block.V is definitely unassigned after every
assert
statement that occurs in thetry
block.V is definitely unassigned before every
break
statement that belongs to thetry
block and whose break target contains (or is) thetry
statement.V is definitely unassigned before every
continue
statement that belongs to thetry
block and whose continue target contains thetry
statement.
If a try
statement does not have a finally
block, then this rule also applies:
- V is [un]assigned after the
try
statement iff V is [un]assigned after thetry
block and V is [un]assigned after everycatch
block in thetry
statement.
If a try
statement does have a finally
block, then these rules also apply:
V is definitely assigned after the
try
statement iff at least one of the following is true:V is definitely assigned after the
try
block and V is definitely assigned after everycatch
block in thetry
statement.V is definitely assigned after the
finally
block.
V is definitely unassigned after the
try
statement iff V is definitely unassigned after thefinally
block.V is definitely assigned before the
finally
block iff V is definitely assigned before thetry
statement.V is definitely unassigned before the
finally
block iff all of the following are true:V is definitely unassigned after the
try
block.V is definitely unassigned before every
return
statement that belongs to thetry
block.V is definitely unassigned after e in every statement of the form
throw
e that belongs to thetry
block.V is definitely unassigned after every
assert
statement that occurs in thetry
block.V is definitely unassigned before every
break
statement that belongs to thetry
block and whose break target contains (or is) thetry
statement.V is definitely unassigned before every
continue
statement that belongs to thetry
block and whose continue target contains thetry
statement.V is definitely unassigned after every
catch
block of thetry
statement.
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.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.