Preview Language Specification for JEP 325: Switch Expressions

This document describes changes to the Java Language Specification to enhance the switch statement, including:

A new body form that evaluates expressions or blocks without fallthrough

A new switch expression which, along with a new break statement form, allows a switch to produce a value

See JEP 325 for an overview.

Changes are described with respect to existing sections of the Java Language Specification. 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 5: Conversions and Contexts

Every expression written in the Java programming language either produces no result (15.1) or has a type that can be deduced at compile time (15.3). When an expression appears in most contexts, it must be compatible with a type expected in that context; this type is called the target type. For convenience, compatibility of an expression with its surrounding context is facilitated in two ways:

First, for some expressions, termed poly expressions (15.2), the deduced type can be influenced by the target type. The same expression can have different types in different contexts.

Second, after the type of the expression has been deduced, an implicit conversion from the type of the expression to the target type can sometimes be performed.

If neither strategy is able to produce the appropriate type, a compile-time error occurs.

The rules determining whether an expression is a poly expression, and if so, its type and compatibility in a particular context, vary depending on the kind of context and the form of the expression. In addition to influencing the type of the expression, the target type may in some cases influence the run time behavior of the expression in order to produce a value of the appropriate type.

Similarly, the rules determining whether a target type allows an implicit conversion vary depending on the kind of context, the type of the expression, and, in one special case, the value of a constant expression ( 15.28 15.29). A conversion from type S to type T allows an expression of type S to be treated at compile time as if it had type T instead. In some cases this will require a corresponding action at run time to check the validity of the conversion or to translate the run-time value of the expression into a form appropriate for the new type T.

Example 5.0-1. Conversions at Compile Time and Run Time A conversion from type Object to type Thread requires a run-time check to make sure that the run-time value is actually an instance of class Thread or one of its subclasses; if it is not, an exception is thrown.

A conversion from type Thread to type Object requires no run-time action; Thread is a subclass of Object , so any reference produced by an expression of type Thread is a valid reference value of type Object .

A conversion from type int to type long requires run-time sign-extension of a 32-bit integer value to the 64-bit long representation. No information is lost.

A conversion from type double to type long requires a non-trivial translation from a 64-bit floating-point value to the 64-bit integer representation. Depending on the actual run-time value, information may be lost.

The conversions possible in the Java programming language are grouped into several broad categories:

Identity conversions

Widening primitive conversions

Narrowing primitive conversions

Widening reference conversions

Narrowing reference conversions

Boxing conversions

Unboxing conversions

Unchecked conversions

Capture conversions

String conversions

Value set conversions

There are six kinds of conversion contexts in which poly expressions may be influenced by context or implicit conversions may occur. Each kind of context has different rules for poly expression typing and allows conversions in some of the categories above but not others. The contexts are:

Assignment contexts (5.2, 15.26), in which an expression's value is bound to a named variable. Primitive and reference types are subject to widening, values may be boxed or unboxed, and some primitive constant expressions may be subject to narrowing. An unchecked conversion may also occur.

Strict invocation contexts (5.3, 15.9, 15.12), in which an argument is bound to a formal parameter of a constructor or method. Widening primitive, widening reference, and unchecked conversions may occur.

Loose invocation contexts (5.3, 15.9, 15.12), in which, like strict invocation contexts, an argument is bound to a formal parameter. Method or constructor invocations may provide this context if no applicable declaration can be found using only strict invocation contexts. In addition to widening and unchecked conversions, this context allows boxing and unboxing conversions to occur.

String contexts (5.4, 15.18.1), in which a value of any type is converted to an object of type String .

Casting contexts (5.5), in which an expression's value is converted to a type explicitly specified by a cast operator (15.16). Casting contexts are more inclusive than assignment or loose invocation contexts, allowing any specific conversion other than a string conversion, but certain casts to a reference type are checked for correctness at run time.

Numeric contexts (5.6), in which the operands of a numeric operator or some other expressions that operate on numbers may be widened to a common type so that an operation can be performed .

The term "conversion" is also used to describe, without being specific, any conversions allowed in a particular context. For example, we say that an expression that is the initializer of a local variable is subject to "assignment conversion", meaning that a specific conversion will be implicitly chosen for that expression according to the rules for the assignment context.

5.6 Numeric Contexts

Numeric contexts apply to the operands of an arithmetic operator arithmetic operators, and some other expressions that operate on numbers.

Numeric contexts allow the use of:

an identity conversion (5.1.1)

a widening primitive conversion (5.1.2)

a widening reference conversion (5.1.5) followed by an unboxing conversion

a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion

an unboxing conversion (5.1.8)

an unboxing conversion followed by a widening primitive conversion

A numeric promotion is a process by which , given an arithmetic operator and its argument expressions, the arguments are one or more expressions in a numeric context are converted to an inferred target type T. T is chosen during promotion such that each argument expression can be converted to T and the arithmetic operation , in the case of an arithmetic operation, the operation is defined for values of type T.

Numeric promotion applies the following rules: If any expression is of a reference type, it is subjected to unboxing conversion (5.1.8).

Next, a target type T is chosen, and widening primitive conversion (5.1.2) and narrowing primitive conversion (5.1.3) are applied to some expressions as specified by the following rules: If any expression is of type double , then T is double , and other expressions that are not of type double are widened to double . Otherwise, if any expression is of type float , then T is float and other expressions that are not of type float are widened to float . Otherwise, if any expression is of type long , then T is long and other expressions that are not of type long are widened to long . Otherwise, if any expression is of type int and is not a constant expression, then T is int and other expressions that are not of type int are widened to int . Otherwise, if any expression is of type short , and every other expression is either of type short , or of type byte , or a constant expression of type int with a value that is representable in the type short , then T is short , the byte expressions are widened to short , and the int expressions are narrowed to short . Otherwise, if any expression is of type byte , and every other expression is either of type byte or a constant expression of type int with a value that is representable in the type byte , then T is byte and the int expressions are narrowed to byte . Otherwise, if any expression is of type char , and every other expression is either of type char or a constant expression of type int with a value that is representable in the type char , then T is char and the int expressions are narrowed to char . Otherwise, T is int and all the expressions that are not of type int are widened to int .

After the conversion(s), if any, value set conversion (5.1.13) is then applied to each expression.

The two kinds of numeric promotion are unary numeric promotion (5.6.1) and binary numeric promotion (5.6.2).

The following subsections are small enough that they can be removed, with their contents collapsed into this section.

5.6.1 Unary Numeric Promotion

Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type: If the operand is of compile-time type Byte , Short , Character , or Integer , it is subjected to unboxing conversion (5.1.8). The result is then promoted to a value of type int by a widening primitive conversion (5.1.2) or an identity conversion (5.1.1).

Otherwise, if the operand is of compile-time type Long , Float , or Double , it is subjected to unboxing conversion (5.1.8).

Otherwise, if the operand is of compile-time type byte , short , or char , it is promoted to a value of type int by a widening primitive conversion (5.1.2).

Otherwise, a unary numeric operand remains as is and is not converted. After the conversion(s), if any, value set conversion (5.1.13) is then applied.

A unary numeric promotion applies numeric promotion to an operand expression and a notional non-constant expression of type int .

Unary numeric promotion is performed on expressions in the following situations:

Each dimension expression in an array creation expression (15.10.1)

The index expression in an array access expression (15.10.3)

The operand of a unary plus operator + (15.15.3)

The operand of a unary minus operator - (15.15.4)

The operand of a bitwise complement operator ~ (15.15.5)

Each operand, separately, of a shift operator << , >> , or >>> (15.19). A long shift distance (right operand) does not promote the value being shifted (left operand) to long .

5.6.2 Binary Numeric Promotion

When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order: If any operand is of a reference type, it is subjected to unboxing conversion (5.1.8). Widening primitive conversion (5.1.2) is applied to convert either or both operands as specified by the following rules: If either operand is of type double , the other is converted to double .

Otherwise, if either operand is of type float , the other is converted to float .

Otherwise, if either operand is of type long , the other is converted to long .

Otherwise, both operands are converted to type int . After the conversion(s), if any, value set conversion (5.1.13) is then applied to each operand.

A binary numeric promotion applies numeric promotion to two operand expressions and a notional non-constant expression of type int .

Binary numeric promotion is performed on the operands of certain operators:

The multiplicative operators * , / , and % (15.17)

The addition and subtraction operators for numeric types + and - (15.18.2)

The numerical comparison operators < , <= , > , and >= (15.20.1)

The numerical equality operators == and != (15.21.1)

The integer bitwise operators & , ^ , and | (15.22.1)

In certain cases, the conditional operator ? : (15.25)

Numeric promotion is performed directly on expressions in the following situations:

The second and third operand of a numeric conditional expression ([15.25.2])

The result expressions of a switch expression, if the type of each result expression is convertible to a numeric type (15.28.1)

Chapter 11: Exceptions

11.2 Compile-Time Checking of Exceptions

11.2.1 Exception Analysis of Expressions

A class instance creation expression (15.9) can throw an exception class E iff either:

The expression is a qualified class instance creation expression and the qualifying expression can throw E; or

Some expression of the argument list can throw E; or

E is one of the exception types of the invocation type of the chosen constructor (15.12.2.6); or

The class instance creation expression includes a ClassBody, and some instance initializer or instance variable initializer in the ClassBody can throw E.

A method invocation expression (15.12) can throw an exception class E iff either:

The method invocation expression is of the form Primary . [TypeArguments] Identifier and the Primary expression can throw E; or

Some expression of the argument list can throw E; or

E is one of the exception types of the invocation type of the chosen method (15.12.2.6).

A switch expression (15.28) can throw an exception class E iff either:

The selector expression can throw E; or

Some expression or statement in the switch block can throw E.

A lambda expression (15.27) can throw no exception classes.

For every other kind of expression, the expression can throw an exception class E iff one of its immediate subexpressions can throw E.

Note that a method reference expression (15.13) of the form Primary :: [TypeArguments] Identifier can throw an exception class if the Primary subexpression can throw an exception class. In contrast, a lambda expression can throw nothing, and has no immediate subexpressions on which to perform exception analysis. It is the body of a lambda expression, containing expressions and statements, that can throw exception classes.

11.2.2 Exception Analysis of Statements

A throw statement (14.18) whose thrown expression has static type E and is not a final or effectively final exception parameter can throw E or any exception class that the thrown expression can throw.

For example, the statement throw new java.io.FileNotFoundException(); can throw java.io.FileNotFoundException only. Formally, it is not the case that it "can throw" a subclass or superclass of java.io.FileNotFoundException .

A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:

E is an exception class that the try block of the try statement which declares C can throw; and

E is assignment compatible with any of C's catchable exception classes; and

E is not assignment compatible with any of the catchable exception classes of the catch clauses declared to the left of C in the same try statement.

A try statement (14.20) can throw an exception class E iff either:

The try block can throw E, or an expression used to initialize a resource (in a try -with-resources statement) can throw E, or the automatic invocation of the close() method of a resource (in a try -with-resources statement) can throw E, and E is not assignment compatible with any catchable exception class of any catch clause of the try statement, and either no finally block is present or the finally block can complete normally; or

Some catch block of the try statement can throw E and either no finally block is present or the finally block can complete normally; or

A finally block is present and can throw E.

An explicit constructor invocation statement (8.8.7.1) can throw an exception class E iff either:

Some expression of the constructor invocation's parameter list can throw E; or

E is determined to be an exception class of the throws clause of the constructor that is invoked (15.12.2.6).

A switch statement (14.11) can throw an exception class E iff either:

The selector expression can throw E; or

Some expression or statement in the switch block can throw E.

Any other statement S can throw an exception class E iff an expression or statement immediately contained in S can throw E.

Chapter 14: Blocks and Statements

14.1 Normal and Abrupt Completion of Statements

Every statement has a normal mode of execution in which certain computational steps are carried out. The following sections describe the normal mode of execution for each kind of statement.

If all the steps are carried out as described, with no indication of abrupt completion, the statement is said to complete normally. However, certain events may prevent a statement from completing normally:

The break (14.15), continue (14.16), and return (14.17) statements cause a transfer of control that may prevent normal completion of statements that contain them.

Evaluation of certain expressions may throw exceptions from the Java Virtual Machine (15.6). An explicit throw (14.18) statement also results in an exception. An exception causes a transfer of control that may prevent normal completion of statements.

If such an event occurs, then execution of one or more statements may be terminated before all steps of their normal mode of execution have completed; such statements are said to complete abruptly.

An abrupt completion always has an associated reason, which is one of the following:

A break with no label or value

A break with a given label

A break with a given value

A continue with no label

A continue with a given label

A return with no value

A return with a given value

A throw with a given value, including exceptions thrown by the Java Virtual Machine

The terms "complete normally" and "complete abruptly" also apply to the evaluation of expressions (15.6). The only reason an expression can complete abruptly is that an exception is thrown, because of either a throw with a given value (14.18) or a run-time exception or error (Chapter 11 (Exceptions), 15.6).

If a statement evaluates an expression, abrupt completion of the expression always causes the immediate abrupt completion of the statement, with the same reason. All succeeding steps in the normal mode of execution are not performed.

Unless otherwise specified in this chapter, abrupt completion of a substatement causes the immediate abrupt completion of the statement itself, with the same reason, and all succeeding steps in the normal mode of execution of the statement are not performed.

Unless otherwise specified, a statement completes normally if all expressions it evaluates and all substatements it executes complete normally.

14.11 The switch Statement

Much of this section has been moved into subsections.

The switch statement transfers control to one of several statements depending on the value of an expression. This expression is known as the selector expression.

SwitchStatement: switch ( Expression ) SwitchBlock

SwitchBlock: { {SwitchBlockStatementGroup} {SwitchLabel} } SwitchBlockStatementGroup: SwitchLabels BlockStatements SwitchLabels: SwitchLabel {SwitchLabel} SwitchLabel: case ConstantExpression : case EnumConstantName : default : EnumConstantName: Identifier

The type of the Expression must be char , byte , short , int , Character , Byte , Short , Integer , String , or an enum type (8.9), or a compile-time error occurs.

14.11.1 The Switch Block

SwitchBlock: { SwitchLabeledRule {SwitchLabeledRule} } { {SwitchLabeledStatementGroup} {SwitchLabel : } } SwitchLabeledRule: SwitchLabeledExpression SwitchLabeledBlock SwitchLabeledThrowStatement SwitchLabeledExpression: SwitchLabel -> Expression ; SwitchLabeledBlock: SwitchLabel -> Block SwitchLabeledThrowStatement: SwitchLabel -> ThrowStatement SwitchLabel: case CaseConstant { , CaseConstant} default CaseConstant: ConditionalExpression SwitchLabeledStatementGroup: SwitchLabel : {SwitchLabel : } BlockStatements

The body of both a switch statement and a switch expression (15.28) is known as a switch block. This block can consist of either:

Switch labeled rules, which use -> to introduce either a switch labeled expression, block, or throw statement; or Switch labeled statement groups, which use : to introduce switch labeled block statements.

Any statement immediately contained by the switch block may be labeled with one or more switch labels, which are case or default labels. Every case label has a case constant, which is either a constant expression or the name of an enum constant. Switch labels and their case constants are said to be associated with the switch statement.

Every case constant associated with a given switch block must be either a constant expression (15.29]) or the name of an enum constant, or a compile-time error occurs.

This excludes the possibility of using null as a case constant.

Given a switch statement, all of the following must be true or a compile-time error occurs: Every case constant associated with the switch statement must be assignment compatible with the type of the switch statement's Expression (5.2).

If the type of the switch statement's Expression is an enum type, then every case constant associated with the switch statement must be an enum constant of that type.

No two of the case constants associated with the switch statement have the same value.

No case constant associated with the switch statement is null .

At most one default label is associated with the switch statement.

A switch block is said to be compatible with the type of the selector expression, T, if both of the following are true: Every case constant associated with the switch block is assignment compatible with T (5.2).

If T is an enum type, then every case constant associated with the switch block is an enum constant of type T. At run time, the value of the selector expression is compared with each case constant (if the selector expression is a reference type that is not the type String , then it is first subject to an unboxing conversion (5.1.8)): If one of the case constants is equal to the value of the selector expression, then we say that the case label matches.

If no case label matches but there is a default label, then we say that the default label matches.

The prohibition against using null as a case constant prevents code being written that can never be executed. If the switch statement's Expression selector expression is of a reference type, that is, String or a boxed primitive type or an enum type, then an exception will be thrown will occur if the Expression evaluates to null at run time. In the judgment of the designers of the Java programming language, this is a better outcome than silently skipping the entire switch statement or choosing to execute the statements (if any) after the default label (if any) either the switch block not matching or even the default label matching.

A Java compiler is encouraged (but not required) to provide a warning if a switch on an enum-valued expression lacks a default label and lacks case labels for one or more of the enum's constants. Such a switch will silently do nothing if the expression evaluates to one of the missing constants.

In C and C++ the body of a switch statement can be a statement and statements with case labels heads do not have to be immediately contained by that statement. Consider the simple loop: for (i = 0; i < n; ++i) foo(); where n is known to be positive. A trick known as Duff's device can be used in C or C++ to unroll the loop, but this is not valid code in the Java programming language: int q = (n+7)/8; switch (n%8) { case 0: do { foo(); // Great C hack, Tom, case 7: foo(); // but it's not valid here. case 6: foo(); case 5: foo(); case 4: foo(); case 3: foo(); case 2: foo(); case 1: foo(); } while (--q > 0); } Fortunately, this trick does not seem to be widely known or used. Moreover, it is less needed nowadays; this sort of code transformation is properly in the province of state-of-the-art optimizing compilers.

14.11.2 The switch Block of a switch Statement

Given a switch statement, all of the following must be true or a compile-time error occurs: The switch block must be compatible with the type of the selector expression.

No two of the case constants associated with the switch block may have the same value.

At most one default label is associated with the switch block. Switch labeled rules in switch statements differ from those in switch expressions (15.28). In switch statements they must be switch labeled statement expressions, whereas in switch expressions they may be any switch labeled expression (15.28.1).

14.11.3 Execution of a switch statement

A switch statement is executed by first evaluating the Expression. If the Expression evaluates to null , a NullPointerException is thrown and the entire switch statement completes abruptly for that reason. Otherwise, if the result is of type Character , Byte , Short , or Integer , it is subject to unboxing conversion (5.1.8). If evaluation of the Expression or the subsequent unboxing conversion (if any) completes abruptly for some reason, the switch statement completes abruptly for the same reason. Otherwise, execution continues by comparing the value of the Expression with each case constant, and there is a choice: If one of the case constants is equal to the value of the expression, then we say that the case label matches. Equality is defined in terms of the == operator (15.21) unless the value of the expression is a String , in which case equality is defined in terms of the equals method of class String . All statements after the matching case label in the switch block, if any, are executed in sequence. If all these statements complete normally, or if there are no statements after the matching case label, then the entire switch statement completes normally.

If no case label matches but there is a default label, then all statements after the default label in the switch block, if any, are executed in sequence. If all these statements complete normally, or if there are no statements after the default label, then the entire switch statement completes normally.

If no case label matches and there is no default label, then no further action is taken and the switch statement completes normally.

When the switch statement is executed, first the selector expression is evaluated: If evaluation of the selector expression completes abruptly for some reason, the switch statement completes abruptly for the same reason. If the selector expression evaluates to null , then a NullPointerException is thrown and the entire switch statement completes abruptly for that reason. Otherwise, execution continues by determining if a switch label associated with the switch block matches the value of the selector expression: If no switch label matches, then the entire switch statement completes normally. If a switch label matches, then one of the following applies: If it labels a statement expression, then the statement expression is evaluated. If the result of evaluation is a value, it is discarded. If the evaluation completes normally, then the switch statement completes normally.

If it labels a statement, then the statement is executed. If this statement completes normally, then the switch statement completes normally.

If it labels a statement group, then all the statements in the switch block that follow it are executed in order. If these statements complete normally, then the switch statement completes normally.

Otherwise, there are no statements that follow it in the switch block, and the switch statement completes normally.

If any statement immediately contained by the Block body of the switch statement execution of any statement or expression completes abruptly, it is handled as follows:

If execution of the Statement a statement completes abruptly because of a break with no label an empty break statement , no further action is taken and the switch statement completes normally.

If execution of the Statement a statement or expression completes abruptly for any other reason, the switch statement completes abruptly for the same reason. The case of abrupt completion because of a value break statement is prohibited by (14.15). The case of abrupt completion because of a break with a label labeled break statement is handled by the general rule for labeled statements (14.7).

14.15 The break Statement

A break statement transfers control out of an enclosing statement, or causes an enclosing switch expression to produce a specified value.

BreakStatement: break [~~ Identifier ~~] ; break Expression ; break ;

There are three kinds of break statement:

A break statement with label Identifier; or, more succinctly, a labeled break statement. A break statement with value Expression; or, more succinctly, a value break statement. A break statement with no label or value; or, more succinctly, an empty break statement.

A break statement with no label An empty break statement attempts to transfer control to the innermost enclosing switch , while , do , or for statement of the immediately enclosing method or initializer; this statement, which is called the break target, then immediately completes normally.

To be precise, a break statement with no label always completes abruptly, the reason being a break with no label.

If no switch , while , do , or for statement in the immediately enclosing method, constructor, or initializer contains the break statement, a compile-time error occurs.

A value break statement attempts to transfer control to the innermost enclosing switch expression; this expression, which is called the break target, then immediately completes normally and the value of the Expression becomes the value of the switch expression.

A labeled break statement with label Identifier attempts to transfer control to the enclosing labeled statement (14.7) that has the same Identifier as its label; this statement, which is called the break target, then immediately completes normally.

A labeled break statement with label Identifier attempts to transfer control to the enclosing labeled statement (14.7) that has the same Identifier as its label; this statement, which is called the break target, then immediately completes normally. In this case, the break target need not be a switch , while , do , or for statement.

To be precise, a break statement with label Identifier always completes abruptly, the reason being a break with label Identifier.

A break statement must refer to a label within the immediately enclosing method, constructor, initializer, or lambda body. There are no non-local jumps. If no labeled statement with Identifier as its label in the immediately enclosing method, constructor, initializer, or lambda body contains the break statement, a compile-time error occurs.

It is a compile-time error if a break statement has no break target, or if the break target contains any method, constructor, initializer, lambda expression, or switch expression that encloses the break statement.

It is a compile-time error if the break target of a value break statement contains any switch , while , do or for statement that encloses the value break statement.

It is a compile-time error if a value break statement is contained in a labeled statement, where Expression is a simple name (15.14.1) that is the same identifier as the label.

It is a compile-time error if the Expression of a value break statement is void (15.1).

Execution of an empty break statement always completes abruptly, the reason being a break with no label.

Execution of a value break statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the break statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the break statement completes abruptly, the reason being a break with value V.

Execution of a labeled break statement with label Identifier always completes abruptly, the reason being a break with label Identifier.

It can be seen, then, that a break statement always completes abruptly.

The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements (14.20) within the break target whose try blocks or catch clauses contain the break statement, then any finally clauses of those try statements are executed, in order, innermost to outermost, before control is transferred to the break target. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a break statement.

14.16 The continue Statement

A continue statement may occur only in a while , do , or for statement; statements of these three kinds are called iteration statements. Control passes to the loop-continuation point of an iteration statement.

ContinueStatement: continue [~~ Identifier ~~] ; continue ;

There are two kinds of continue statement:

A continue statement with label Identifier; or, more succinctly, a labeled continue statement. A continue statement with no label; or, more succinctly, an empty continue statement.

A continue statement with no label An empty continue statement attempts to transfer control to the innermost enclosing while , do , or for statement of the immediately enclosing method, constructor, or initializer ; this statement, which is called the continue target, then immediately ends the current iteration and begins a new one.

To be precise, such a continue statement always completes abruptly, the reason being a continue with no label.

If no while , do , or for statement of the immediately enclosing method, constructor, or initializer contains the continue statement, a compile-time error occurs.

A labeled continue statement with label Identifier attempts to transfer control to the enclosing labeled statement (14.7) that has the same Identifier as its label; that statement, which is called the continue target, then immediately ends the current iteration and begins a new one.

To be precise, a continue statement with label Identifier always completes abruptly, the reason being a continue with label Identifier.

The continue target of a labeled continue statement must be a while , do , or for statement, or a compile-time error occurs.

A continue statement must refer to a label within the immediately enclosing method, constructor, initializer, or lambda body. There are no non-local jumps. If no labeled statement with Identifier as its label in the immediately enclosing method, constructor, initializer, or lambda body contains the continue statement, a compile-time error occurs.

It is a compile-time error if a continue statement has no continue target, or if the continue target contains any method, constructor, initializer, lambda expression, or switch expression that contains the continue statement.

Execution of an empty continue statement always completes abruptly, the reason being a continue with no label.

Execution of a labeled continue statement with label Identifier always completes abruptly, the reason being a continue with label Identifier.

It can be seen, then, that a continue statement always completes abruptly.

See the descriptions of the while statement (14.12), do statement (14.13), and for statement (14.14) for a discussion of the handling of abrupt termination because of continue .

The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements (14.20) within the continue target whose try blocks or catch clauses contain the continue statement, then any finally clauses of those try statements are executed, in order, innermost to outermost, before control is transferred to the continue target. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a continue statement.

14.17 The return Statement

A return statement returns control to the invoker of a method (8.4, 15.12) or constructor (8.8, 15.9).

ReturnStatement: return [~~ Expression ~~] ; return ;

There are two kinds of return statement:

A return statement with value Expression; or, more succinctly, a value return statement. A return statement with no value; or, more succinctly, an empty return statement.

A return statement is contained in the innermost constructor, method, initializer, or lambda expression whose body encloses the return statement.

A return statement attempts to transfer control to the invoker of the innermost enclosing constructor, method, intializer, or lambda expression; this declaration is called the return target. In the case of a value return statement, the value of the Expression becomes the value of the invocation.

It is a compile-time error if a return statement has no return target, or if the return target contains any enclosing method, constructor, initializer, lambda expression, or switch expression that contains the return statement.

It is a compile-time error if a return statement is contained in the return target for a return statement is an instance initializer or a static initializer (8.6, 8.7).

A return statement with no Expression must be contained in one of the following, or a compile-time error occurs:

A method that is declared, using the keyword void , not to return a value (8.4.5)

A constructor (8.8.7)

A lambda expression (15.27)

It is a compile-time error if the return target of an empty return statement is a method, and that method is not declared 'void'.

A return statement with no Expression attempts to transfer control to the invoker of the method, constructor, or lambda body that contains it. To be precise, a return statement with no Expression always completes abruptly, the reason being a return with no value.

A return statement with an Expression must be contained in one of the following, or a compile-time error occurs:

A method that is declared to return a value

A lambda expression

The Expression must denote a variable or a value, or a compile-time error occurs.

When a return statement with an Expression appears in a method declaration, the Expression must be assignable (5.2) to the declared return type of the method, or a compile-time error occurs.

It is a compile-time error if the return target of a value return statement is a constructor or a method that is declared void ; or if the return target is a method with declared return type T, and Expression is not assignable (5.2) to T.

Execution of an empty return statement always completes abruptly, the reason being a return with no value.

A return statement with an Expression attempts to transfer control to the invoker of the method or lambda body that contains it; the value of the Expression becomes the value of the method invocation. More precisely, execution of such a return statement first evaluates the Expression. Execution of a value return statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the return statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the return statement completes abruptly, the reason being a return with value V.

If the expression is of type float and is not FP-strict (15.4), then the value may be an element of either the float value set or the float-extended-exponent value set (4.2.3). If the expression is of type double and is not FP-strict, then the value may be an element of either the double value set or the double-extended-exponent value set.

It can be seen, then, that a return statement always completes abruptly.

The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements (14.20) within the method or constructor whose try blocks or catch clauses contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.

14.21 Unreachable Statements

It is a compile-time error if a statement cannot be executed because it is unreachable.

This section is devoted to a precise explanation of the word "reachable." The idea is that there must be some possible execution path from the beginning of the constructor, method, instance initializer, or static initializer that contains the statement to the statement itself. The analysis takes into account the structure of statements. Except for the special treatment of while , do , and for statements whose condition expression has the constant value true , the values of expressions are not taken into account in the flow analysis.

For example, a Java compiler will accept the code: { int n = 5; while (n > 7) k = 2; } even though the value of n is known at compile time and in principle it can be known at compile time that the assignment to k can never be executed.

The rules in this section define two technical terms:

whether a statement is reachable

whether a statement can complete normally

The definitions here allow a statement to complete normally only if it is reachable.

To shorten the description of the rules, the customary abbreviation "iff" is used to mean "if and only if."

A reachable break statement exits a statement if, within the break target, either there are no try statements whose try blocks contain the break statement, or there are try statements whose try blocks contain the break statement and all finally clauses of those try statements can complete normally.

This definition is based on the logic around "attempts to transfer control" in 14.15.

A continue statement continues a do statement if, within the do statement, either there are no try statements whose try blocks contain the continue statement, or there are try statements whose try blocks contain the continue statement and all finally clauses of those try statements can complete normally.

The rules are as follows:

The block that is the body of a constructor, method, instance initializer, or static initializer static initializer, lambda expression, or switch expression is reachable.

An empty block that is not a switch block can complete normally iff it is reachable. A non-empty block that is not a switch block can complete normally iff the last statement in it can complete normally. The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable. Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.

A local class declaration statement can complete normally iff it is reachable.

A local variable declaration statement can complete normally iff it is reachable.

An empty statement can complete normally iff it is reachable.

A labeled statement can complete normally if at least one of the following is true: The contained statement can complete normally. There is a reachable break statement that exits the labeled statement. The contained statement is reachable iff the labeled statement is reachable.

An expression statement can complete normally iff it is reachable.

An if - then statement can complete normally iff it is reachable. The then -statement is reachable iff the if - then statement is reachable. An if - then - else statement can complete normally iff the then -statement can complete normally or the else -statement can complete normally. The then -statement is reachable iff the if - then - else statement is reachable. The else -statement is reachable iff the if - then - else statement is reachable. This handling of an if statement, whether or not it has an else part, is rather unusual. The rationale is given at the end of this section.

An assert statement can complete normally iff it is reachable.

A switch statement whose switch block is empty, or contains only switch labels, completes normally.

A switch statement with a switch block that consists of switch labeled statement groups can complete normally iff at least one of the following is true: The switch block is empty or contains only switch labels. The last statement in the switch block can complete normally. There is at least one switch label after the last switch block statement group. The switch block does not contain a default label. There is a reachable break statement that exits the switch statement.

A switch statement with a switch block that consists of switch labeled rules can complete normally iff at least one of the following is true: One of the switch labeled rules is a switch labeled expression (which is necessarily a statement expression). One of the switch labeled rules is a switch labeled block that can complete normally. One of the switch labeled rules is a switch labeled block that contains a reachable break statement that exits the switch statement.

A switch block is reachable iff its switch statement is reachable.

A statement in a switch block that consists of switch labeled statement groups is reachable iff its switch statement the switch block is reachable and at least one of the following is true: It bears a case or default label. There is a statement preceding it in the switch block and that preceding statement can complete normally.

A switch labeled block in a switch block is reachable iff the switch block is reachable.

A while statement can complete normally iff at least one of the following is true: The while statement is reachable and the condition expression is not a constant expression ( 15.28 15.29 ) with value true . There is a reachable break statement that exits the while statement. The contained statement is reachable iff the while statement is reachable and the condition expression is not a constant expression whose value is false .

A do statement can complete normally iff at least one of the following is true: The contained statement can complete normally and the condition expression is not a constant expression ( 15.28 15.29 ) with value true . The do statement contains a reachable continue statement with no label, and the do statement is the innermost while , do , or for statement that contains that continue statement, and the continue statement continues that do statement, and the condition expression is not a constant expression with value true . The do statement contains a reachable continue statement with a label L, and the do statement has label L, and the continue statement continues that do statement, and the condition expression is not a constant expression with value true . There is a reachable break statement that exits the do statement. The contained statement is reachable iff the do statement is reachable.

A basic for statement can complete normally iff at least one of the following is true: The for statement is reachable, there is a condition expression, and the condition expression is not a constant expression ( 15.28 15.29 ) with value true . There is a reachable break statement that exits the for statement. The contained statement is reachable iff the for statement is reachable and the condition expression is not a constant expression whose value is false .

An enhanced for statement can complete normally iff it is reachable.

A break , continue , return , or throw statement cannot complete normally.

A synchronized statement can complete normally iff the contained statement can complete normally. The contained statement is reachable iff the synchronized statement is reachable.

A try statement can complete normally iff both of the following are true: The try block can complete normally or any catch block can complete normally. If the try statement has a finally block, then the finally block can complete normally.

The try block is reachable iff the try statement is reachable.

A catch block C is reachable iff both of the following are true: Either the type of C's parameter is an unchecked exception type or Exception or a superclass of Exception , or some expression or throw statement in the try block is reachable and can throw a checked exception whose type is assignable to the type of C's parameter. (An expression is reachable iff the innermost statement containing it is reachable.) See 15.6 for normal and abrupt completion of expressions. There is no earlier catch block A in the try statement such that the type of C's parameter is the same as or a subclass of the type of A's parameter.

The Block of a catch block is reachable iff the catch block is reachable.

If a finally block is present, it is reachable iff the try statement is reachable.

One might expect the if statement to be handled in the following manner:

An if - then statement can complete normally iff at least one of the following is true: The if - then statement is reachable and the condition expression is not a constant expression whose value is true . The then -statement can complete normally. The then -statement is reachable iff the if - then statement is reachable and the condition expression is not a constant expression whose value is false .

An if - then - else statement can complete normally iff the then -statement can complete normally or the else -statement can complete normally. The then -statement is reachable iff the if - then - else statement is reachable and the condition expression is not a constant expression whose value is false . The else -statement is reachable iff the if - then - else statement is reachable and the condition expression is not a constant expression whose value is true .

This approach would be consistent with the treatment of other control structures. However, in order to allow the if statement to be used conveniently for "conditional compilation" purposes, the actual rules differ.

As an example, the following statement results in a compile-time error:

while (false) { x=3; }

because the statement x=3; is not reachable; but the superficially similar case:

if (false) { x=3; }

does not result in a compile-time error. An optimizing compiler may realize that the statement x=3; will never be executed and may choose to omit the code for that statement from the generated class file, but the statement x=3; is not regarded as "unreachable" in the technical sense specified here.

The rationale for this differing treatment is to allow programmers to define "flag" variables such as:

static final boolean DEBUG = false;

and then write code such as:

if (DEBUG) { x=3; }

The idea is that it should be possible to change the value of DEBUG from false to true or from true to false and then compile the code correctly with no other changes to the program text.

Conditional compilation comes with a caveat. If a set of classes that use a "flag" variable - or more precisely, any static constant variable (4.12.4) - are compiled and conditional code is omitted, it does not suffice later to distribute just a new version of the class or interface that contains the definition of the flag. The classes that use the flag will not see its new value, so their behavior may be surprising. In essence, a change to the value of a flag is binary compatible with pre-existing binaries (no LinkageError occurs) but not behaviorally compatible.

Another reason for "inlining" values of static constant variables is because of switch statements. They are the only kind of statement that relies on constant expressions, namely that each case label of a switch statement must be a constant expression whose value is different than every other case label. case labels are often references to static constant variables so it may not be immediately obvious that all the labels have different values. If it is proven that there are no duplicate labels at compile time, then inlining the values into the class file ensures there are no duplicate labels at run time either - a very desirable property.

Chapter 15: Expressions

15.1 Evaluation, Denotation, and Result

When an expression in a program is evaluated (executed), the result denotes one of three things:

A variable (4.12) (in C, this would be called an lvalue)

A value (4.2, 4.3)

Nothing (the expression is said to be void)

If an expression denotes a variable, and a value is required for use in further evaluation, then the value of that variable is used. In this context, if the expression denotes a variable or a value, we may speak simply of the value of the expression.

Value set conversion (5.1.13) is applied to the result of every expression that produces a value, including when the value of a variable of type float or double is used.

An expression denotes nothing if and only if it is a method invocation (15.12) that invokes a method that does not return a value, that is, a method declared void (8.4). Such an expression can be used only as an expression statement (14.8) or as the single expression of a lambda body (15.27.2), because every other context in which an expression can appear requires the expression to denote something. An expression statement or lambda body that is a method invocation may also invoke a method that produces a result; in this case the value returned by the method is quietly discarded.

Evaluation of an expression can produce side effects, because expressions may contain embedded assignments, increment operators, decrement operators, and method invocations, as well as statements contained in switch expressions.

An expression occurs in either:

The declaration of some (class or interface) type that is being declared: in a field initializer, in a static initializer, in an instance initializer, in a constructor declaration, in a method declaration, or in an annotation.

An annotation on a package declaration or on a top level type declaration.

15.2 Forms of Expressions

Expressions can be broadly categorized into one of the following syntactic forms:

Expression names (6.5.6)

Primary expressions (15.8 - 15.13)

Unary operator expressions (15.14 - 15.16)

Binary operator expressions (15.17 - 15.24, and 15.26)

Ternary operator expressions (15.25)

Lambda expressions (15.27)

Precedence among operators is managed by a hierarchy of grammar productions. The lowest precedence operator is the arrow of a lambda expression ( -> ), followed by the assignment operators. Thus, all expressions are syntactically included in the LambdaExpression and AssignmentExpression nonterminals:

Expression: LambdaExpression AssignmentExpression

When some expressions appear in certain contexts, they are considered poly expressions. The following forms of expressions may be poly expressions:

Parenthesized expressions (15.8.5)

Class instance creation expressions (15.9)

Method invocation expressions (15.12)

Method reference expressions (15.13)

Conditional expressions (15.25)

Lambda expressions (15.27)

switch expressions (15.28)

The rules determining whether an expression of one of these forms is a poly expression are given in the individual sections that specify these forms of expressions.

Expressions that are not poly expressions are standalone expressions. Standalone expressions are expressions of the forms above when determined not to be poly expressions, as well as all expressions of all other forms. Expressions of all other forms are said to have a standalone form.

Some expressions have a value that can be determined at compile time. These are constant expressions ( 15.28 15.29).

15.6 Normal and Abrupt Completion of Evaluation

Every expression has a normal mode of evaluation in which certain computational steps are carried out. The following sections describe the normal mode of evaluation for each kind of expression.

If all the steps are carried out without an exception being thrown, the expression is said to complete normally.

If, however, evaluation of an expression throws an exception, then the expression is said to complete abruptly. An abrupt completion always has an associated reason, which is always a throw with a given value.

Run-time exceptions are thrown by the predefined operators as follows:

A class instance creation expression (15.9.4), array creation expression (15.10.2), method reference expression (15.13.3), array initializer expression (10.6), string concatenation operator expression (15.18.1), or lambda expression (15.27.4) throws an OutOfMemoryError if there is insufficient memory available.

An array creation expression (15.10.2) throws a NegativeArraySizeException if the value of any dimension expression is less than zero.

An array access expression (15.10.4) throws a NullPointerException if the value of the array reference expression is null .

An array access expression (15.10.4) throws an ArrayIndexOutOfBoundsException if the value of the array index expression is negative or greater than or equal to the length of the array.

A field access expression (15.11) throws a NullPointerException if the value of the object reference expression is null .

A method invocation expression (15.12) that invokes an instance method throws a NullPointerException if the target reference is null .

A cast expression (15.16) throws a ClassCastException if a cast is found to be impermissible at run time.

An integer division (15.17.2) or integer remainder (15.17.3) operator throws an ArithmeticException if the value of the right-hand operand expression is zero.

An assignment to an array component of reference type (15.26.1), a method invocation expression (15.12), or a prefix or postfix increment (15.14.2, 15.15.1) or decrement operator (15.14.3, 15.15.2) may all throw an OutOfMemoryError as a result of boxing conversion (5.1.7).

An assignment to an array component of reference type (15.26.1) throws an ArrayStoreException when the value to be assigned is not compatible with the component type of the array (10.5).

A switch expression (15.28) may throw an IncompatibleClassChangeError if no switch label matches the value of the selector expression.

A method invocation expression can also result in an exception being thrown if an exception occurs that causes execution of the method body to complete abruptly.

A class instance creation expression can also result in an exception being thrown if an exception occurs that causes execution of the constructor to complete abruptly.

Various linkage and virtual machine errors may also occur during the evaluation of an expression. By their nature, such errors are difficult to predict and difficult to handle.

If an exception occurs, then evaluation of one or more expressions may be terminated before all steps of their normal mode of evaluation are complete; such expressions are said to complete abruptly.

If evaluation of an expression requires evaluation of a subexpression, then abrupt completion of the subexpression always causes the immediate abrupt completion of the expression itself, with the same reason, and all succeeding steps in the normal mode of evaluation are not performed.

The terms "complete normally" and "complete abruptly" are also applied to the execution of statements (14.1). A statement may complete abruptly for a variety of reasons, not just because an exception is thrown.

15.12 Method Invocation Expressions

15.12.2 Compile-Time Step 2: Determine Method Signature

15.12.2.1 Identify Potentially Applicable Methods

The class or interface determined by compile-time step 1 (15.12.1) is searched for all member methods that are potentially applicable to this method invocation; members inherited from superclasses and superinterfaces are included in this search.

In addition, if the form of the method invocation expression is MethodName - that is, a single Identifier - then the search for potentially applicable methods also examines all member methods that are imported by single-static-import declarations and static-import-on-demand declarations of the compilation unit where the method invocation occurs (7.5.3, 7.5.4) and that are not shadowed at the point where the method invocation appears.

A member method is potentially applicable to a method invocation if and only if all of the following are true:

The name of the member is identical to the name of the method in the method invocation.

The member is accessible (6.6) to the class or interface in which the method invocation appears. Whether a member method is accessible at a method invocation depends on the access modifier ( public , protected , no modifier (package access), or private ) in the member's declaration, and on the inheritance of the member by the class or interface determined by compile-time step 1, and on where the method invocation appears.

If the member is a fixed arity method with arity n, the arity of the method invocation is equal to n, and for all i (1 ≤ i ≤ n), the i'th argument of the method invocation is potentially compatible, as defined below, with the type of the i'th parameter of the method.

If the member is a variable arity method with arity n, then for all i (1 ≤ i ≤ n-1), the i'th argument of the method invocation is potentially compatible with the type of the i'th parameter of the method; and, where the nth parameter of the method has type T [] , one of the following is true: The arity of the method invocation is equal to n-1. The arity of the method invocation is equal to n, and the nth argument of the method invocation is potentially compatible with either T or T [] . The arity of the method invocation is m, where m > n, and for all i (n ≤ i ≤ m), the i'th argument of the method invocation is potentially compatible with T.

If the method invocation includes explicit type arguments, and the member is a generic method, then the number of type arguments is equal to the number of type parameters of the method. This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored. This rule stems from issues of compatibility and principles of substitutability. Since interfaces or superclasses may be generified independently of their subtypes, we may override a generic method with a non-generic one. However, the overriding (non-generic) method must be applicable to calls to the generic method, including calls that explicitly pass type arguments. Otherwise the subtype would not be substitutable for its generified supertype.

If the search does not yield at least one method that is potentially applicable, then a compile-time error occurs.

An expression is potentially compatible with a target type according to the following rules:

A lambda expression (15.27) is potentially compatible with a functional interface type T (9.8) if all of the following are true: The arity of the function type of T (9.9) is the same as the arity of the lambda expression. If the function type of T has a void return, then the lambda body is either a statement expression (14.8) or a void-compatible block (15.27.2). If the function type of T has a (non- void ) return type, then the lambda body is either an expression or a value-compatible block (15.27.2).

A method reference expression (15.13) is potentially compatible with a functional interface type T if, where the arity of the function type of T is n, there exists at least one potentially applicable method when the method reference expression targets the function type with arity n (15.13.1), and one of the following is true: The method reference expression has the form ReferenceType :: [TypeArguments] Identifier and at least one potentially applicable method is either (i) static and supports arity n, or (ii) not static and supports arity n-1. The method reference expression has some other form and at least one potentially applicable method is not static .

A lambda expression or a method reference expression is potentially compatible with a type variable if the type variable is a type parameter of the candidate method.

A parenthesized expression (15.8.5) is potentially compatible with a type if its contained expression is potentially compatible with that type.

A conditional expression (15.25) is potentially compatible with a type if each of its second and third operand expressions are potentially compatible with that type.

A switch expression (15.28) is potentially compatible with a type if all of its result expressions are potentially compatible with that type.

A class instance creation expression, a method invocation expression, or an expression of a standalone form (15.2) is potentially compatible with any type.

The definition of potential applicability goes beyond a basic arity check to also take into account the presence and "shape" of functional interface target types. In some cases involving type argument inference, a lambda expression appearing as a method invocation argument cannot be properly typed until after overload resolution. These rules allow the form of the lambda expression to still be taken into account, discarding obviously incorrect target types that might otherwise cause ambiguity errors.

15.12.2.5 Choosing the Most Specific Method

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error. In cases such as an explicitly typed lambda expression argument (15.27.1) or a variable arity invocation (15.12.2.4), some flexibility is allowed to adapt one signature to the other.

One applicable method m 1 is more specific than another applicable method m 2 , for an invocation with argument expressions e 1 , ..., e k , if any of the following are true:

m 2 is generic, and m 1 is inferred to be more specific than m 2 for argument expressions e 1 , ..., e k by 18.5.4.

m 2 is not generic, and m 1 and m 2 are applicable by strict or loose invocation, and where m 1 has formal parameter types S 1 , ..., S n and m 2 has formal parameter types T 1 , ..., T n , the type S i is more specific than T i for argument e i for all i (1 ≤ i ≤ n, n = k).

m 2 is not generic, and m 1 and m 2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m 1 are S 1 , ..., S k and the first k variable arity parameter types of m 2 are T 1 , ..., T k , the type S i is more specific than T i for argument e i for all i (1 ≤ i ≤ k). Additionally, if m 2 has k+1 parameters, then the k+1'th variable arity parameter type of m 1 is a subtype of the k+1'th variable arity parameter type of m 2 .

The above conditions are the only circumstances under which one method may be more specific than another.

A type S is more specific than a type T for any expression if S <: T (4.10).

A functional interface type S is more specific than a functional interface type T for an expression e if all of the following are true:

The interface of S is neither a superinterface nor a subinterface of the interface of T. If S or T is an intersection type, it is not the case that any interface of S is a superinterface or a subinterface of any interface of T. (The "interfaces of" an intersection type refers here to the set of interfaces that appear as (possibly parameterized) interface types in the intersection.)

Let MT S be the function type of the capture of S, and let MT T be the function type of T. MT S and MT T must have the same type parameters (if any) (8.4.4).

Let P 1 , ..., P n be the formal parameter types of MT S , adapted to the type parameters of MT T . Let P 1 ', ..., P n ' be the formal parameter types of the function type of S (without capture), adapted to the type parameters of MT T . Let Q 1 , ..., Q n be the formal parameter types of MT T . Then, for all i (1 ≤ i ≤ n), Q i <: P i and Q i = P i '. Generally, this rule asserts that the formal parameter types derived from S and T are the same. But in the case in which S is a wildcard-parameterized type, the check is more complex in order to allow capture variables to occur in formal parameter types: first, each formal parameter type of T must be a subtype of the corresponding formal parameter type of the capture of S; second, after mapping the wildcards to their bounds (9.9), the formal parameter types of the resulting function types are the same.

Let R S be the return type of MT S , adapted to the type parameters of MT T , and let R T be the return type of MT T . One of the following must be true: e is an explicitly typed lambda expression (15.27.1), and one of the following is true: R T is void . R S <: R T . R S and R T are functional interface types, and there is at least one result expression, and R S is more specific than R T for each result expression of e. The result expression of a lambda expression with a block body is defined in 15.27.2; the result expression of a lambda expression with an expression body is simply the body itself. R S is a primitive type, and R T is a reference type, and there is at least one result expression, and each result expression of e is a standalone expression (15.2) of a primitive type. R S is a reference type, and R T is a primitive type, and there is at least one result expression, and each result expression of e is either a standalone expression of a reference type or a poly expression. e is an exact method reference expression (15.13.1), and one of the following is true: R T is void . R S <: R T . R S is a primitive type, R T is a reference type, and the compile-time declaration for the method reference has a return type which is a primitive type. R S is a reference type, R T is a primitive type, and the compile-time declaration for the method reference has a return type which is a reference type. e is a parenthesized expression, and one of these conditions applies recursively to the contained expression. e is a conditional expression, and, for each of the second and third operands, one of these conditions applies recursively. e is a switch expression, and, for each of its result expressions, one of these conditions applies recursively.



A method m 1 is strictly more specific than another method m 2 if and only if m 1 is more specific than m 2 and m 2 is not more specific than m 1 .

A method is said to be maximally specific for a method invocation if it is accessible and applicable and there is no other method that is accessible and applicable that is strictly more specific.

If there is exactly one maximally specific method, then that method is in fact the most specific method; it is necessarily more specific than any other accessible method that is applicable. It is then subjected to some further compile-time checks as specified in 15.12.3.

It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:

If all the maximally specific methods have override-equivalent signatures (8.4.2), and exactly one of the maximally specific methods is concrete (that is, neither abstract nor default), then it is the most specific method.

Otherwise, if all the maximally specific methods have override-equivalent signatures, and all the maximally specific methods are abstract or default, and the declarations of these methods have the same erased parameter types, and at least one maximally specific method is preferred according to the rules below, then the most specific method is chosen arbitrarily among the subset of the maximally specific methods that are preferred. The most specific method is then considered to be abstract . A maximally specific method is preferred if it has: a signature that is a subsignature of every maximally specific method's signature; and a return type R (possibly void ), where either R is the same as every maximally specific method's return type, or R is a reference type and is a subtype of every maximally specific method's return type (after adapting for any type parameters (8.4.4) if the two methods have the same signature). If no preferred method exists according to the above rules, then a maximally specific method is preferred if it: has a signature that is a subsignature of every maximally specific method's signature; and is return-type-substitutable (8.4.5) for every maximally specific method. The thrown exception types of the most specific method are derived from the throws clauses of the maximally specific methods, as follows: If the most specific method is generic, the throws clauses are first adapted to the type parameters of the most specific method (8.4.4). If the most specific method is not generic but at least one maximally specific method is generic, the throws clauses are first erased. Then, the thrown exception types include every type E which satisfies the following constraints: E is mentioned in one of the throws clauses. For each throws clause, E is a subtype of some type named in that clause. These rules for deriving a single method type from a group of overloaded methods are also used to identify the function type of a functional interface (9.9).

Otherwise, the method invocation is ambiguous, and a compile-time error occurs.

15.15 Unary Operators Expressions

The operators + , - , ++ , -- , ~ , ! , and the cast operator (15.16) are called the unary operators, which are used to form unary expressions. In addition, the switch expression (15.28) is treated grammatically as a unary expression.

UnaryExpression: PreIncrementExpression PreDecrementExpression + UnaryExpression - UnaryExpression UnaryExpressionNotPlusMinus PreIncrementExpression: ++ UnaryExpression PreDecrementExpression: -- UnaryExpression UnaryExpressionNotPlusMinus: PostfixExpression ~ UnaryExpression ! UnaryExpression CastExpression SwitchExpression

The following production from 15.16 is shown here for convenience: CastExpression: ( PrimitiveType ) UnaryExpression ( ReferenceType {AdditionalBound} ) UnaryExpressionNotPlusMinus ( ReferenceType {AdditionalBound} ) LambdaExpression #

Expressions with unary operators group right-to-left, so that -~x means the same as -(~x) .

This portion of the grammar contains some tricks to avoid two potential syntactic ambiguities.

The first potential ambiguity would arise in expressions such as (p)+q , which looks, to a C or C++ programmer, as though it could be either a cast to type p of a unary + operating on q , or a binary addition of two quantities p and q . In C and C++, the parser handles this problem by performing a limited amount of semantic analysis as it parses, so that it knows whether p is the name of a type or the name of a variable.

Java takes a different approach. The result of the + operator must be numeric, and all type names involved in casts on numeric values are known keywords. Thus, if p is a keyword naming a primitive type, then (p)+q can make sense only as a cast of a unary expression. However, if p is not a keyword naming a primitive type, then (p)+q can make sense only as a binary arithmetic operation. Similar remarks apply to the - operator. The grammar shown above splits CastExpression into two cases to make this distinction. The nonterminal UnaryExpression includes all unary operators, but the nonterminal UnaryExpressionNotPlusMinus excludes uses of all unary operators that could also be binary operators, which in Java are + and - .

The second potential ambiguity is that the expression (p)++ could, to a C or C++ programmer, appear to be either a postfix increment of a parenthesized expression or the beginning of a cast, for example, in (p)++q . As before, parsers for C and C++ know whether p is the name of a type or the name of a variable. But a parser using only one-token lookahead and no semantic analysis during the parse would not be able to tell, when ++ is the lookahead token, whether (p) should be considered a Primary expression or left alone for later consideration as part of a CastExpression.

In Java, the result of the ++ operator must be numeric, and all type names involved in casts on numeric values are known keywords. Thus, if p is a keyword naming a primitive type, then (p)++ can make sense only as a cast of a prefix increment expression, and there had better be an operand such as q following the ++ . However, if p is not a keyword naming a primitive type, then (p)++ can make sense only as a postfix increment of p . Similar remarks apply to the -- operator. The nonterminal UnaryExpressionNotPlusMinus therefore also excludes uses of the prefix operators ++ and -- .

15.25 Conditional Operator ? :

The conditional operator ? : uses the boolean value of one expression to decide which of two other expressions should be evaluated.

ConditionalExpression: ConditionalOrExpression ConditionalOrExpression ? Expression : ConditionalExpression ConditionalOrExpression ? Expression : LambdaExpression #

The conditional operator is syntactically right-associative (it groups right-to-left). Thus, a?b:c?d:e?f:g means the same as a?b:(c?d:(e?f:g)) .

The conditional operator has three operand expressions. ? appears between the first and second expressions, and : appears between the second and third expressions.

The first expression must be of type boolean or Boolean , or a compile-time error occurs.

It is a compile-time error for either the second or the third operand expression to be an invocation of a void method.

In fact, by the grammar of expression statements (14.8), it is not permitted for a conditional expression to appear in any context where an invocation of a void method could appear.

There are three kinds of conditional expressions, classified according to the second and third operand expressions: boolean conditional expressions, numeric conditional expressions, and reference conditional expressions. The classification rules are as follows:

If both the second and the third operand expressions are boolean expressions, the conditional expression is a boolean conditional expression. For the purpose of classifying a conditional, the following expressions are boolean expressions: An expression of a standalone form (15.2) that has type boolean or Boolean . A parenthesized boolean expression (15.8.5). A class instance creation expression (15.9) for class Boolean . A method invocation expression (15.12) for which the chosen most specific method (15.12.2.5) has return type boolean or Boolean . Note that, for a generic method, this is the type before instantiating the method's type arguments. A boolean conditional expression. A switch expression whose result expressions all have type boolean or Boolean .

If both the second and the third operand expressions are numeric expressions, the conditional expression is a numeric conditional expression. For the purpose of classifying a conditional, the following expressions are numeric expressions: An expression of a standalone form (15.2) with a type that is convertible to a numeric type (4.2, 5.1.8). A parenthesized numeric expression (15.8.5). A class instance creation expression (15.9) for a class that is convertible to a numeric type. A method invocation expression (15.12) for which the chosen most specific method (15.12.2.5) has a return type that is convertible to a numeric type. Note that, for a generic method, this is the type before instantiating the method's type arguments. A numeric conditional expression. A switch expression whose result expressions all have types that are convertible to a numeric type.

Otherwise, the conditional expression is a reference conditional expression.

The process for determining the type of a conditional expression depends on the kind of conditional expression, as outlined in the following sections.

...

15.25.1 Boolean Conditional Expressions

Boolean conditional expressions are standalone expressions (15.2).

The type of a boolean conditional expression is determined as follows:

If the second and third operands are both of type Boolean , the conditional expression has type Boolean .

Otherwise, the conditional expression has type boolean .

15.25.2 Numeric Conditional Expressions

Numeric conditional expressions are standalone expressions (15.2).

The type of a numeric conditional expression is determined as follows:

If the second and third operands have the same type, then that is the type of the conditional expression.

If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (5.1.7) to T, then the type of the conditional expression is T.

If one of the operands is of type byte or Byte and the other is of type short or Short , then the type of the conditional expression is short .

If one of the operands is of type T where T is byte , short , or char , and the other operand is a constant expression ( 15.28 15.29 ) of type int whose value is representable in type T, then the type of the conditional expression is T.

If one of the operands is of type T, where T is Byte , Short , or Character , and the other operand is a constant expression of type int whose value is representable in the type U which is the result of applying unboxing conversion to T, then the type of the conditional expression is U.

Otherwise, binary numeric promotion (5.6.2) is applied to the second and third operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs value set conversion (5.1.13) and may perform unboxing conversion (5.1.8).

15.25.3 Reference Conditional Expressions

A reference conditional expression is a poly expression if it appears in an assignment context or an invocation context (5.2. 5.3). Otherwise, it is a standalone expression.

Where a poly reference conditional expression appears in a context of a particular kind with target type T, its second and third operand expressions similarly appear in a context of the same kind with target type T.

A poly reference conditional expression is compatible with a target type T if its second and third operand expressions are compatible with T.

The type of a poly reference conditional expression is the same as its target type.

The type of a standalone reference conditional expression is determined as follows:

If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

If the type of one of the second and third operands is the null type, and the type of the other operand is a reference type, then the type of the conditional expression is that reference type.

Otherwise, the second and third operands are of types S 1 and S 2 respectively. Let T 1 be the type that results from applying boxing conversion to S 1 , and let T 2 be the type that results from applying boxing conversion to S 2 . The type of the conditional expression is the result of applying capture conversion (5.1.10) to lub(T 1 , T 2 ).

Because reference conditional expressions can be poly expressions, they can "pass down" context to their operands. This allows lambda expressions and method reference expressions to appear as operands:

return ... ? (x `->` x) : (x `->` -x);

It also allows use of extra information to improve type checking of generic method invocations. Prior to Java SE 8, this assignment was well-typed:

List<String> ls = Arrays.asList();

but this was not:

List<String> ls = ... ? Arrays.asList() : Arrays.asList("a","b");

The rules above allow both assignments to be considered well-typed.

Note that a reference conditional expression does not have to contain a poly expression as an operand in order to be a poly expression. It is a poly expression simply by virtue of the context in which it appears. For example, in the following code, the conditional expression is a poly expression, and each operand is considered to be in an assignment context targeting Class<? super Integer> :

If the conditional expression was not a poly expression, then a compile-time error would occur, as its type would be lub( Class<Integer> , Class<Number> ) = Class<? extends Number> which is incompatible with the return type of choose .

15.28 switch Expressions

A switch expression is the expression analogue of the switch statement (14.11). It consists of a selector expression and a switch block (14.11.1). A switch expression matches the value of the selector expression against the switch labels associated with the switch block to determine which code contained in the switch block to execute to return a value. In contrast to a switch statement, the switch block is checked to ensure that the switch expression either completes normally with a value or completes abruptly. SwitchExpression: switch ( Expression ) SwitchBlock The type of the selector expression must be char , byte , short , int , Character , Byte , Short , Integer , String , or an enum type (8.9), or a compile-time error occurs.

15.28.1 The switch block of a switch expression

Given a switch expression, all of the following must be true or a compile-time error occurs: The switch block must not be empty.

The switch block must be compatible with the type of the selector expression.

No two of the case constants associated with the switch block may have the same value.

Either there is a default label associated with the switch block; or if the type of the selector expression is an enum type, then the set of all the case constants associated with the switch block must contain all the enum constants of that enum type.

If the switch block consists of switch labeled rules, then any switch labeled block (14.11.1) must complete abruptly.

If the switch block consists of switch labeled statement groups, then the last statement in the switch block must complete abruptly, and the switch block must not have any switch labels after the last switch labeled statement group. Switch labeled rules in switch expressions differ from those in switch statements (14.11.2). In switch expressions they may be any switch labeled expression, whereas in switch statements they must be switch labeled statement expressions (14.8). The result expressions of a switch expression are determined as follows: If the switch block consists of switch labeled rules, then each is considered in turn: if it is a switch labeled expression, then this expression is a result expression of the switch expression. if it is a switch labeled block, then every expression immediately contained in a value break statement in the block whose break target is the given switch expression is a result expression of the switch expression

If the switch block consists of switch labeled statement groups, then every expression immediately contained in a value break statement in the block whose break target is the given switch expression is a result expression of the switch expression. It is a compile-time error if a switch expression has no result expressions. A switch expression is a poly expression if it appears in an assignment context or an invocation context (5.2, 5.3). Otherwise, it is a standalone expression. Where a poly switch expression appears in a context of a particular kind with target type T, its result expressions similarly appear in a context of the same kind with target type T. A poly switch expression is compatible with a target type T if each of its result expressions is compatible with T. The type of a poly switch expression is the same as its target type. The type of a standalone switch expression is determined as follows: If the result expressions all have the same type (which may be the null type), then that is the type of the switch expression.

Otherwise, if the type of each result expression is boolean or Boolean , an unboxing conversion (5.1.8) is applied to each result expression of type Boolean , and the switch expression has type boolean .

Otherwise, if the type of each result expression is convertible to a numeric type (5.1.8), the type of the switch expression is the result of numeric promotion (5.6) applied to the result expressions.

Otherwise, boxing conversion (5.1.7) is applied to each result expression that has a primitive type, after which the type of the switch expression is the result of applying capture conversion (5.1.10) to the least upper bound (4.10.4) of the types of the result expressions.

15.28.2 Run-Time Evaluation of switch Expressions

When the switch expression is executed, first the selector expression is evaluated; exactly one of three outcomes are possible. If evaluation of the selector expression completes abruptly for some reason, the switch expression completes abruptly for the same reason. If the selector expression evaluates to null , then a NullPointerException is thrown and the entire switch expression completes abruptly for that reason. Otherwise, execution continues by determining if a switch label associated with the switch block matches the value of the selector expression. If no switch label matches, then an IncompatibleClassChangeError is thrown and the entire switch expression completes abruptly for that reason. If a switch label matches, then one of the following applies: If it labels an expression, then this expression is evaluated. If the result of evaluation is a value, then the switch expression completes normally with the same value.

If it labels a statement, then the statement is executed.

Otherwise, all the statements in the switch block after the matching switch label are executed in order. If execution of any statement or expression completes abruptly, it is handled as follows: If execution of an expression completes abruptly for a reason, then the switch expression completes abruptly for the same reason.

If execution of a statement completes abruptly for the reason of a break with value V, then the switch expression completes normally and the value of the switch expression is V.

If execution of a statement completes abruptly for any reason other than a break with value, then the switch expression completes abruptly for the same reason.

15.28 15.29 Constant Expressions

ConstantExpression: Expression

A constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

Literals of primitive type and literals of type String (3.10.1, 3.10.2, 3.10.3, 3.10.4, 3.10.5)

Casts to primitive types and casts to type String (15.16)

The unary operators + , - , ~ , and ! (but not ++ or -- ) (15.15.3, 15.15.4, 15.15.5, 15.15.6)

The multiplicative operators * , / , and % (15.17)

The additive operators + and - (15.18)

The shift operators << , >> , and >>> (15.19)

The relational operators < , <= , > , and >= (but not instanceof ) (15.20)

The equality operators == and != (15.21)

The bitwise and logical operators & , ^ , and | (15.22)

The conditional-and operator && and the conditional-or operator || (15.23, 15.24)

The ternary conditional operator ? : (15.25)

Parenthesized expressions (15.8.5) whose contained expression is a constant expression.

Simple names (6.5.6.1) that refer to constant variables (4.12.4).

Qualified names (6.5.6.2) of the form TypeName . Identifier that refer to constant variables (4.12.4).

Constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern .

A constant expression is always treated as FP-strict (15.4), even if it occurs in a context where a non-constant expression would not be considered to be FP-strict.

Constant expressions are used as case labels in switch statements and switch expressions (14.11, 15.28) and have a special significance in assignment contexts (5.2) and the initialization of a class or interface (12.4.2). They may also govern the ability of a while , do , or for statement to complete normally (14.21), and the type of a conditional operator ? : with numeric operands.

Example 15.28-1 15.29-1. Constant Expressions true (short)(1*2*3*4*5*6) Integer.MAX_VALUE / 2 2.0 * Math.PI "The integer " + Long.MAX_VALUE + " is mighty big."

Chapter 16: Definite Assignment

16.1 Definite Assignment and Expressions

16.1.7 switch Expressions

Suppose that the switch expression has result expressions e1 , ..., en , all of which are boolean-valued. The following rules apply only if the switch block of a switch expression (15.28) consists of switch labeled statement groups: V is definitely assigned after a switch expression when true iff for every value break statement with expression e in the switch block that may exit the switch expression, V is definitely assigned after e when true.

V is definitely assigned after a switch expression when false iff for every value break statement with expression e in the switch block that may exit the switch expression, V is definitely assigned after e when false.

V is definitely unassigned after a switch expression when true iff for every value break statement with expression e in the switch block that may exit the switch expression, V is definitely unassigned before the value break statement and V is definitely unassigned after e when true.

V is definitely unassigned after a switch expression when false iff for every value break statement with expression e in the switch block that may exit the switch expression, V is definitely unassigned before the value break statement and V is definitely unassigned after e when false.

V is [un]assigned before the selector expression iff V is [un]assigned before the switch statement.

V is [un]assigned before the first statement of the first switch labeled statement group in the switch block iff V is [un]assigned after the selector expression.

V is [un]assigned before the first statement of any switch labeled statement group other than the first iff V is [un]assigned after the selector expression and V is [un]assigned after the preceding statement. The following rules apply only if the switch block of a switch expression consists of switch labeled rules: V is definitely assigned after a switch expression when true iff for every switch labeled rule one of the following is true: It is a switch labeled expression e and V is definitely assigned after e when true. It is a switch labeled block b and for every value break statement expression e contained in b that may exit the switch expression, V is definitely assigned after e when true. It is a switch labeled throw statement.

V is definitely assigned after a switch expression when false iff for every switch labeled rule one of the following is true: It is a switch labeled expression e and V is definitely assigned after e when false. It is a switch labeled block b and for every value break statement expression e contained in b that may exit the switch expression, V is definitely assigned after e when false. It is a switch labeled throw statement.

V is definitely unassigned after a switch expression when true iff for every switch labeled rule one of the following is true: It is a switch labeled expression e and V is definitely unassigned after e when true . It is a switch labeled block b and for every value break statement expression e contained in b that may exit the switch expression, V is definitely unassigned before the value break statement and V is definitely unassigned after e when true. It is a switch labeled throw statement.

V is definitely unassigned after a switch expression when false iff for every switch labeled rule one of the following is true: It is a switch labeled expression e and V is definitely unassigned after e when false. It is a switch labeled block b and for every value break statement expression e contained in b that may exit the switch expression, V is definitely unassigned before the value break statement and V is definitely unassigned after e when false. It is a switch labeled throw statement.

V is [un]assigned before any switch labeled expression or statement in the switch block iff V is [un]assigned after the selector expression.

16.1.8 switch Expressions

Suppose that the switch expression has result expressions e1 , ..., en , not all of which are boolean-valued. The following rules apply only if the switch block of a switch expression (15.28) consists of switch labeled statement groups: V is definitely assigned after a switch expression iff for every value break statement with expression e in the switch block that may exit the switch expression, either V is definitely assigned before the value break statement or V is definitely assigned after e .

V is definitely unassigned after a switch expression iff for every value break statement with expression e in the switch block that may exit the switch expression, V is definitely unassigned before the value break statement and V is definitely unassigned after e .

V is [un]assigned before the selector expression iff V is [un]assigned before the switch statement.

V is [un]assigned before the first statement of the first switch labeled statement group in the switch block iff V is [un]assigned after the selector expression.

V is [un]assigned before the first statement of any switch labeled statement group other than the first iff V is [un]assigned after the selector expression and V is [un]assigned after the preceding statement. The following rules apply only if the switch block of a switch expression consists of switch labeled rules: V is definitely assigned after a switch expression iff for every switch labeled rule one of the following is true: It is a switch labeled expression e and V is definitely assigned after e . It is a switch labeled block b and for every value break statement expression e contained in b that may exit the switch expression, either V is definitely assigned before the value break statement or V is definitely assigned after e . It is a switch labeled throw statement.

V is definitely unassigned after a switch expression iff for every switch labeled rule one of the following is true: It is a switch labeled expression e and V is definitely unassigned after e . It is a switch labeled block b and for every value break statement expression e contained in b that may exit the switch expression, V is definitely unassigned before the value break statement and V is definitely unassigned after e . It is a switch labeled throw statement.

V is [un]assigned before any switch labeled expression or statement in the switch block iff V is [un]assigned after the selector expression.

16.1.7 16.1.9 Other Expressions of Type boolean

Suppose that e is an expression of type boolean and is not a boolean constant expression, logical complement expression ! a, conditional-and expression a && b, conditional-or expression a || b, or conditional expression a ? b : c.

V is [un]assigned after e when true iff V is [un]assigned after e.

V is [un]assigned after e when false iff V is [un]assigned after e.

16.1.8 16.1.10 Assignment Expressions

Consider an assignment expression a = b, a += b, a -= b, a *= b, a /= b, a %= b, a <<= b, a >>= b, a >>>= b, a &= b, a |= b, or a ^= b (15.26).

V is definitely assigned after the assignment expression iff either: a is V, or V is definitely assigned after b.

V is definitely unassigned after the assignment expression iff a is not V and V is definitely unassigned after b.

V is [un]assigned before a iff V is [un]assigned before the assignment expression.

V is [un]assigned before b iff V is [un]assigned after a.

Note that if a is V and V is not definitely assigned before a compound assignment such as a &= b, then a compile-time error will necessarily occur. The first rule for definite assignment stated above includes the disjunct "a is V" even for compound assignment expressions, not just simple assignments, so that V will be considered to have been definitely assigned 