Copyright © 2018 Oracle America, Inc. Legal Notice.
This document proposes changes to the Java Language Specification to support extensions to the switch
statement so that it can be used as either a statement or an expression, along with associated changes to the break
statement. See JEP 325 for an overview.
To assist reading, this document contains complete replacements for sections 5.6, 11.2.1, 11.2.2, 14.1, 14.11, 14.15, 14.16, 14.17, 14.21, 15.1, 15.2, 15.6, 15.12.2.1, 15.12.2.5, 15.15, 15.25, 15.28, 16.2.9, 16.2.13, 18.5.2, and 18.5.4 along with entirely new sections 5.6.3, 15.29, 16.1.7, and 16.1.8. In the replacement sections, new text is highlighted like this and deleted text is highlighted like this.
Numeric contexts apply to the operands of an arithmetic operator, or the result expressions of a switch
expression.
Numeric contexts allow the use of:
an identity conversion (5.1.1)
a widening primitive conversion (5.1.2)
an unboxing conversion (5.1.8) optionally followed by a widening primitive conversion
A numeric promotion is a process by which, given either an arithmetic operator and its argument expressions, or a switch
expression and its result expressions, the arguments subexpressions are converted to an inferred target type T. T is chosen during promotion such that each argument expression subexpression can be converted to T and, in the case of an the arithmetic operation, it is defined for values of type T.
The two three kinds of numeric promotion are unary numeric promotion (5.6.1), and binary numeric promotion (5.6.2), and switch numeric promotion (5.6.3).
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.
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
.
Example 5.6.1-1. Unary Numeric Promotion
class Test {
public static void main(String[] args) {
byte b = 2;
int a[] = new int[b]; // dimension expression promotion
char c = '\u0001';
a[c] = 1; // index expression promotion
a[0] = -c; // unary - promotion
System.out.println("a: " + a[0] + "," + a[1]);
b = -1;
int i = ~b; // bitwise complement promotion
System.out.println("~0x" + Integer.toHexString(b)
+ "==0x" + Integer.toHexString(i));
i = b << 4L; // shift promotion (left operand)
System.out.println("0x" + Integer.toHexString(b)
+ "<<4L==0x" + Integer.toHexString(i));
}
}
This program produces the output:
a: -1,1
~0xffffffff==0x0
0xffffffff<<4L==0xfffffff0
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.
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)
Example 5.6.2-1. Binary Numeric Promotion
class Test {
public static void main(String[] args) {
int i = 0;
float f = 1.0f;
double d = 2.0;
// First int*float is promoted to float*float, then
// float==double is promoted to double==double:
if (i * f == d) System.out.println("oops");
// A char&byte is promoted to int&int:
byte b = 0x1f;
char c = 'G';
int control = c & b;
System.out.println(Integer.toHexString(control));
// Here int:float is promoted to float:float:
f = (b==0) ? i : 4.0f;
System.out.println(1.0/f);
}
}
This program produces the output:
7
0.25
The example converts the ASCII character G
to the ASCII control-G (BEL), by masking off all but the low 5 bits of the character. The 7
is the numeric value of this control character.
When a switch expression applies numeric promotion to a set of result expressions, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:
If any result expression is of a reference type, it is subjected to unboxing conversion (5.1.8).
double
, then other result expressions that are not of type double
are widened to double
.float
, then other result expressions that are not of type float
are widened to float
.long
, then other result expressions that are not of type long
are widened to long
.int
and is not a constant expression, the other result expressions that are not of type int
are widened to int
.char
, and every other result expression is either of type char
, or of type byte
, or a constant expression of type int
with a value that is representable in the type char
, then the byte
results are widened to char
and the int
results are narrowed to char
.short
, and every other result 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 the byte
results are widened to short
and the int
results are narrowed to short
.byte
, and every other result expression is either of type byte
or a constant expression of type int
with a value that is representable in the type byte
, then the int
results are narrowed to byte
.int
are widened to int
.After the conversion(s), if any, value set conversion (5.1.13) is then applied to each result expression.
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.29) 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.
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.
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 ([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.
switch
Statement[Editorial note: The existing section 14.11 is replaced in its entirety with the following.]
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
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.
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.29) is known as a switch block. This block can either be empty, or take one of two forms:
A switch block can consist of one or more switch labeled rules, which is either a switch labeled expression, block, or throw statement.
A switch block can consist of one or more switch labeled statement groups, optionally followed by switch labels. A switch labeled statement group consists of one or more block statements labeled with one or more switch labels.
A switch label can be either a case
label or a default
label. Every case
label has at least one case
constant. case
and default
labels, and the case
constants of case
labels, are said to be associated with the switch block.
Every case
constant associated with a given switch block must be either a constant expression (15.28) or the name of an enum constant, or a compile-time error occurs.
This excludes the possibility of using null
as a case
constant.
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 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 either the switch block not matching or even the default
label matching.
In C and C++ the body of a switch
statement can be a statement and statements with case
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.
A case
label can contain several case
constants, and matches the value of a selector expression if any one of its case
constants matches.
switch (day) {
case SATURDAY, SUNDAY:
// matches if it is a Saturday OR a Sunday
System.out.println("It's the weekend!");
}
switch
statementGiven 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.
If the switch block consists of switch labeled rules, then any switch labeled expression must be a statement expression (14.8).
switch
statementWhen 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:
switch
statement completes normally.switch
statement completes normally.switch
statement completes normally.switch
statement completes normally.If execution of any statement or expression completes abruptly, it is handled as follows:
If execution of a statement completes abruptly because of an empty break
statement, no further action is taken and the switch
statement completes normally.
If execution of 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 labeled break
statement is handled by the general rule for labeled statements (14.7).
When a selector expression matches a switch label within a switch labeled rule, only the labeled expression or statement is executed and nothing else. In the other case, all the block statements in the switch block that follow the switch label are executed, including those that appear after subsequent switch labels. The effect is that, as in C and C++, execution of statements can “fall through labels.”
For example, the program:
class TooMany {
static void howMany(int k) {
switch (k) {
case 1: System.out.print("one ");
case 2: System.out.print("too ");
case 3: System.out.println("many");
}
}
public static void main(String args) {
howMany(3);
howMany(2);
howMany(1);
}
}
contains a switch
block in which the code for each case
falls through into the code for the next case
. As a result, the program prints:
many
too many
one too many
This fall through behaviour can be the cause of subtle bugs. If code is not to fall through case
to case
in this manner, switch labeled rules can be used, or empty break
statements can be used to explicitly indicate where control should be transfered, as follows:
class TwoMany {
static void howManyRule(int k) {
switch (k) {
case 1 -> System.out.println("one");
case 2 -> System.out.println("two");
case 3 -> System.out.println("many");
}
}
static void howManyGroup(int k) {
switch (k) {
case 1: System.out.println("one");
break; // exit the switch
case 2: System.out.println("two");
break; // exit the switch
case 3: System.out.println("many");
break; // not needed, but good style
}
}
public static void main(String args) {
howManyRule(1);
howManyRule(2);
howManyRule(3);
howManyGroup(1);
howManyGroup(2);
howManyGroup(3);
}
}
This program prints:
one
two
many
one
two
many
break
StatementA break
statement transfers control out of an enclosing statement, or causes an enclosing switch
expression to produce a specified value.
BreakStatement:
break
[Identifier];
break
Identifier;
break
Expression;
break
;
There are three kinds of break
statement:
break
statement with label Identifier; or, more succinctly, a labeled break
statement.break
statement with value Expression; or, more succinctly, a value break
statement.break
statement with no label or value; or, more succinctly, an empty break
statement.A break
statement with no label 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 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.
An empty break
statement attempts to transfer control to the innermost enclosing switch
, while
, do
, or for
statement; this statement, which is called the break target, then immediately completes normally.
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.
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.
Example 14.15-1. The break
Statement
In the following example, a mathematical graph is represented by an array of arrays. A graph consists of a set of nodes and a set of edges; each edge is an arrow that points from some node to some other node, or from a node to itself. In this example it is assumed that there are no redundant edges; that is, for any two nodes P
and Q
, where Q
may be the same as P
, there is at most one edge from P
to Q
.
Nodes are represented by integers, and there is an edge from node i
to node edges[i
][j
] for every i
and j
for which the array reference edges[i
][j
] does not throw an ArrayIndexOutOfBoundsException
.
The task of the method loseEdges
, given integers i
and j
, is to construct a new graph by copying a given graph but omitting the edge from node i
to node j
, if any, and the edge from node j
to node i
, if any:
class Graph {
int edges;
public Graph(int edges) { this.edges = edges; }
public Graph loseEdges(int i, int j) {
int n = edges.length;
int newedges = new int[n];
for (int k = 0; k < n; ++k) {
edgelist:
{
int z;
search:
{
if (k == i) {
for (z = 0; z < edges[k].length; ++z) {
if (edges[k][z] == j) break search;
}
} else if (k == j) {
for (z = 0; z < edges[k].length; ++z) {
if (edges[k][z] == i) break search;
}
}
// No edge to be deleted; share this list.
newedges[k] = edges[k];
break edgelist;
} //search
// Copy the list, omitting the edge at position z.
int m = edges[k].length - 1;
int ne = new int[m];
System.arraycopy(edges[k], 0, ne, 0, z);
System.arraycopy(edges[k], z+1, ne, z, m-z);
newedges[k] = ne;
} //edgelist
}
return new Graph(newedges);
}
}
Note the use of two statement labels, edgelist
and search
, and the use of break
statements. This allows the code that copies a list, omitting one edge, to be shared between two separate tests, the test for an edge from node i
to node j
, and the test for an edge from node j
to node i
.
continue
StatementA 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
Identifier;
continue
;
There are two kinds of continue
statement:
continue
statement with label Identifier; or, more succinctly, a labeled continue
statement.continue
statement with no label; or, more succinctly, an empty continue
statement.A continue
statement with no label 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 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 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.
An empty continue
statement attempts to transfer control to the innermost enclosing while
, do
, or for
statement; this statement, which is called the continue target, then immediately ends the current iteration and begins a new one.
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.
The continue target of a labeled continue must be a while
, do
, or for
statement, or 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.
Example 14.16-1. The continue
Statement
In the Graph
class in (14.15), one of the break
statements is used to finish execution of the entire body of the outermost for
loop. This break can be replaced by a continue
if the for
loop itself is labeled:
class Graph {
int edges[][];
public Graph(int[][] edges) { this.edges = edges; }
public Graph loseEdges(int i, int j) {
int n = edges.length;
int[][] newedges = new int[n][];
edgelists:
for (int k = 0; k < n; ++k) {
int z;
search:
{
if (k == i) {
for (z = 0; z < edges[k].length; ++z) {
if (edges[k][z] == j) break search;
}
} else if (k == j) {
for (z = 0; z < edges[k].length; ++z) {
if (edges[k][z] == i) break search;
}
}
// No edge to be deleted; share this list.
newedges[k] = edges[k];
continue edgelists;
} //search
// Copy the list, omitting the edge at position z.
int m = edges[k].length - 1;
int ne[] = new int[m];
System.arraycopy(edges[k], 0, ne, 0, z);
System.arraycopy(edges[k], z+1, ne, z, m-z);
newedges[k] = ne;
} //edgelists
return new Graph(newedges);
}
}
Which to use, if either, is largely a matter of programming style.
return
StatementA return
statement returns control to the invoker of a method (8.4, 15.12), or constructor ([8.8], 15.9).
ReturnStatement:
return
[Expression];
return
Expression;
return
;
There are two kinds of return
statement:
return
statement with value Expression; or, more succinctly, a value return
statement.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 the return target for a return
statement is contained in 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)
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.
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. 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
.
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’.
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.
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.
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, 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) 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) 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) 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.
This ability to “conditionally compile” has no relationship to binary compatibility ([13 (Binary Compatibility)]). If a set of classes that use such a “flag” variable 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, but no LinkageError
will occur. A change to the value of a flag is, therefore, binary compatible with pre-existing binaries, but not behaviorally compatible.
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)
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 or constructor 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.
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)
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.29)
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).
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 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.
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 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 (9.8) if all of the following are true:
The arity of the target type’s function type is the same as the arity of the lambda expression.
If the target type’s function type 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 target type’s function type 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 if, where the type’s function type arity is n, there exists at least one potentially applicable method for the method reference expression 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 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.29) 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.
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 m1
is more specific than another applicable method m2
, for an invocation with argument expressions e1
, …, ek
, if any of the following are true:
m2
is generic, and m1
is inferred to be more specific than m2
for argument expressions e1
, …, ek
by 18.5.4.
m2
is not generic, and m1
and m2
are applicable by strict or loose invocation, and where m1
has formal parameter types S1, …, Sn and m2
has formal parameter types T1, …, Tn, the type Si is more specific than Ti for argument ei
for all i (1 ≤ i ≤ n, n = k).
m2
is not generic, and m1
and m2
are applicable by variable arity invocation, and where the first k variable arity parameter types of m1
are S1, …, Sk and the first k variable arity parameter types of m2
are T1, …, Tk, the type Si is more specific than Ti for argument ei
for all i (1 ≤ i ≤ k). Additionally, if m2
has k+1 parameters, then the k+1’th variable arity parameter type of m1
is a subtype of the k+1’th variable arity parameter type of m2
.
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 T is not a subtype of S and one of the following is true (where U1 … Uk and R1 are the parameter types and return type of the function type of the capture of S, and V1 … Vk and R2 are the parameter types and return type of the function type of T):
If e
is an explicitly typed lambda expression (15.27.1), then one of the following is true:
R2 is void
.
R1 <:
R2.
R1 and R2 are functional interface types, and there is at least one result expression, and R1 is more specific than R2 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.)
R1 is a primitive type, and R2 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.
R1 is a reference type, and R2 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.
If e
is an exact method reference expression (15.13.1), then i) for all i (1 ≤ i ≤ k), Ui is the same as Vi, and ii) one of the following is true:
R2 is void
.
R1 <:
R2.
R1 is a primitive type, R2 is a reference type, and the compile-time declaration for the method reference has a return type which is a primitive type.
R1 is a reference type, R2 is a primitive type, and the compile-time declaration for the method reference has a return type which is a reference type.
If e
is a parenthesized expression, then one of these conditions applies recursively to the contained expression.
If e
is a conditional expression, then for each of the second and third operands, one of these conditions applies recursively.
If e
is a switch
expression, then for each of its result expressions, one of these conditions applies recursively.
A method m1
is strictly more specific than another method m2
if and only if m1
is more specific than m2
and m2
is not more specific than m1
.
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 applicable and accessible 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), then:
If exactly one of the maximally specific methods is concrete (that is, non-abstract
or default), it is the most specific method.
Otherwise, if all the maximally specific methods are abstract
or default, and the signatures of all of the maximally specific methods have the same erasure (4.6), then the most specific method is chosen arbitrarily among the subset of the maximally specific methods that have the most specific return type.
In this case, the most specific method is considered to be abstract
. Also, the most specific method is considered to throw a checked exception if and only if that exception or its erasure is declared in the throws
clauses of each of the maximally specific methods.
Otherwise, the method invocation is ambiguous, and a compile-time error occurs.
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.29) 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
-~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 --
.
? :
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.
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.
The following tables summarize the rules above by giving the type of a conditional expression for all possible types of its second and third operands. bnp(..) means to apply binary numeric promotion. The form “T | bnp(..)” is used where one operand is a constant expression of type int
and may be representable in type T, where binary numeric promotion is used if the operand is not representable in type T. The operand type Object
means any reference type other than the null
type and the eight wrapper classes Boolean
, Byte
, Short
, Character
, Integer
, Long
, Float
, Double
.
[Editorial note: Tables 15.25.A-E will appear here unchanged in the final spec. Not reproduced in this document for brevity.]
At run time, the first operand expression of the conditional expression is evaluated first. If necessary, unboxing conversion is performed on the result.
The resulting boolean
value is then used to choose either the second or the third operand expression:
If the value of the first operand is true
, then the second operand expression is chosen.
If the value of the first operand is false
, then the third operand expression is chosen.
The chosen operand expression is then evaluated and the resulting value is converted to the type of the conditional expression as determined by the rules stated below.
This conversion may include boxing or unboxing conversion (5.1.7, 5.1.8).
The operand expression not chosen is not evaluated for that particular evaluation of the conditional expression.
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.29) and have a special significance for assignment conversion (5.2) and 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. 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."
switch
Expressions[Editorial note: This is a new section.]
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.
switch
expressionGiven 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, or a compile-time error occurs.
No two of the case
constants associated with the switch block may have the same value.
Given a switch
expression, at least one of the following must be true, or a compile-time error occurs:
default
label associated with the switch block.case
constants associated with the switch block must contain all the enum constants of that enum type.Given a switch
expression, if the switch block consists of switch labeled rules, then it is a compile-time error if any switch labeled block can complete normally. If, on the other hand, the switch block consists of switch labeled statement groups, then it is a compile-time error if either the last statement in the switch block can complete normally, or the switch block includes one or more switch labels at the end.
The result expressions of a switch
expression are determined as follows:
switch
expression.break
statement in the block whose break target is the given switch
expression is a result expression of the switch
expressionbreak
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 given by numeric promotion (5.6.3) 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.
switch
expressionWhen 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:
switch
expression completes normally with the same value.If execution of any statement or expression completes abruptly, it is handled as follows:
If execution of a 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.
[Editorial note: Existing section 16.1.7 renumbered to 16.1.9, 16.1.8 renumbered to 16.1.10, 16.1.9 renumbered to 16.1.11, and 16.1.10 renumbered to 16.1.12.]
switch
Expression[Editorial note: This is a new subsection.]
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.29) 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 assigned 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 assigned 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.
switch
Expression[Editorial note: This is a new subsection.]
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.29) 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 assigned 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.
switch
StatementsThe following rules apply only if the switch block of a switch
statement (14.11) is empty, consists of just switch labels, or consists of switch labeled statement groups:
V
is [un]assigned after a switch
statement (14.11) iff all of the following are true:
Either there is a default
label in the switch block or V
is [un]assigned after the switch selector expression.
Either there are no switch labels in the switch block that do not begin a block-statement-group switch labeled statement group (that is, there are no switch labels immediately before the “}
” that ends the switch block) or V
is [un]assigned after the switch selector expression.
Either the switch block contains no block-statement-groups switch labeled statement groups or V
is [un]assigned after the last block-statement block statement of the last block-statement-group switch labeled statement group.
V
is [un]assigned before every break
statement that may exit the switch
statement.
V
is [un]assigned before the switch selector expression iff V
is [un]assigned before the switch
statement.
If a switch block contains at least one block-statement-group switch labeled statement group, then the following rules also apply:
V
is [un]assigned before the first block-statement block statement of the first block-statement-group switch labeled statement group in the switch block iff V
is [un]assigned after the switch selector expression.
V
is [un]assigned before the first block-statement block statement of any block-statement-group switch labeled statement group other than the first iff V
is [un]assigned after the switch selector expression and V
is [un]assigned after the preceding block-statement block statement.
The following rules apply only if the switch block of the switch
statement consists of switch labeled rules:
V
is [un]assigned after a switch
statement iff for every switch labeled rule one of the following is true:
It is a switch labeled expression e
and either V
is [un]assigned after e
or after the selector expression.
It is a switch labeled block b
and either V
is [un]assigned after e
or V
is [un]assigned before every break
statement contained in b
that may exit the switch
statement.
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.
break
, continue
, return
, and throw
StatementsV
is [un]assigned after any break
, continue
, return
, or throw
statement (14.15, 14.16, 14.17, 14.18).The notion that a variable is “[un]assigned after” a statement or expression really means “is [un]assigned after the statement or expression completes normally”. Because a break
, continue
, return
, or throw
statement never completes normally, it vacuously satisfies this notion.
return
statement with e
, throw
statement with e
, or a value break
statement with expression e
, V
is [un]assigned before e
iff V
is [un]assigned before the value return
, throw
, or break
statement.A constraint formula of the form ‹Expression → T› is reduced as follows:
If T is a proper type, the constraint reduces to true if the expression is compatible in a loose invocation context with T (5.3), and false otherwise.
Otherwise, if the expression is a standalone expression (15.2) of type S, the constraint reduces to ‹S → T›.
Otherwise, the expression is a poly expression (15.2). The result depends on the form of the expression:
If the expression is a parenthesized expression of the form (
Expression‘)
, the constraint reduces to ‹Expression’ → T›.
If the expression is a class instance creation expression or a method invocation expression, the constraint reduces to the bound set B3 which would be used to determine the expression’s invocation type when targeting T, as defined in 18.5.2. (For a class instance creation expression, the corresponding “method” used for inference is defined in 15.9.3).
This bound set may contain new inference variables, as well as dependencies between these new variables and the inference variables in T.
If the expression is a conditional expression of the form e1
?
e2
:
e3
, the constraint reduces to two constraint formulas, ‹e2
→ T› and ‹e3
→ T›.
If the expression is a switch
expression with a set of result expressions e1
, …, en
, the constraint reduces to n
constraint formulas, ‹e1
→ T›, …, ‹en
→ T›.
If the expression is a lambda expression or a method reference expression, the result is specified below.
By treating nested generic method invocations as poly expressions, we improve the behavior of inference for nested invocations. For example, the following is illegal in Java SE 7 but legal in Java SE 8:
ProcessBuilder b = new ProcessBuilder(Collections.emptyList());
// ProcessBuilder's constructor expects a List<String>
When both the outer and the nested invocation require inference, the problem is more difficult. For example:
List<String> ls = new ArrayList<>(Collections.emptyList());
Our approach is to “lift” the bounds inferred for the nested invocation (simply { α <:
Object
} in the case of emptyList
) into the outer inference process (in this case, trying to infer β where the constructor is for type ArrayList``<
β>
). We also infer dependencies between the nested inference variables and the outer inference variables (the constraint ‹List``<
α>
→ Collection``<
β>
› would reduce to the dependency α = β). In this way, resolution of the inference variables in the nested invocation can wait until additional information can be inferred from the outer invocation (based on the assignment target, β = String
).
A constraint formula of the form ‹LambdaExpression → T›, where T mentions at least one inference variable, is reduced as follows:
If T is not a functional interface type (9.8), the constraint reduces to false.
Otherwise, let T’ be the ground target type derived from T, as specified in 15.27.3. If 18.5.3 is used to derive a functional interface type which is parameterized, then the test that F<
A’1, …, A’m>
is a subtype of F<
A1, …, Am>
is not performed (instead, it is asserted with a constraint formula below). Let the target function type for the lambda expression be the function type of T’. Then:
If no valid function type can be found, the constraint reduces to false.
Otherwise, the congruence of LambdaExpression with the target function type is asserted as follows:
If the number of lambda parameters differs from the number of parameter types of the function type, the constraint reduces to false.
If the lambda expression is implicitly typed and one or more of the function type’s parameter types is not a proper type, the constraint reduces to false.
This condition never arises in practice, due to the handling of implicitly typed lambda expressions in 18.5.1 and the substitution applied to the target type in 18.5.2.
If the function type’s result is void
and the lambda body is neither a statement expression nor a void-compatible block, the constraint reduces to false.
If the function type’s result is not void
and the lambda body is a block that is not value-compatible, the constraint reduces to false.
Otherwise, the constraint reduces to all of the following constraint formulas:
If the lambda parameters have explicitly declared types F1, …, Fn and the function type has parameter types G1, …, Gn, then i) for all i (1 ≤ i ≤ n), ‹Fi = Gi›, and ii) ‹T’ <:
T›.
If the function type’s return type is a (non-void
) type R, assume the lambda’s parameter types are the same as the function type’s parameter types. Then:
If R is a proper type, and if the lambda body or some result expression in the lambda body is not compatible in an assignment context with R, then false.
Otherwise, if R is not a proper type, then where the lambda body has the form Expression, the constraint ‹Expression → R›; or where the lambda body is a block with result expressions e1
, …, em
, for all i (1 ≤ i ≤ m), ‹ei
→ R›.
The key piece of information to derive from a compatibility constraint involving a lambda expression is the set of bounds on inference variables appearing in the target function type’s return type. This is crucial, because functional interfaces are often generic, and many methods operating on these types are generic, too.
In the simplest case, a lambda expression may simply provide a lower bound for an inference variable:
<T> List<T> makeThree(Factory<T> factory) { ... }
String s = makeThree(() -> "abc").get(2);
In more complex cases, a result expression may be a poly expression - perhaps even another lambda expression - and so the inference variable might be passed through multiple constraint formulas with different target types before a bound is produced.
Most of the work described in this section precedes assertions about the result expressions; its purpose is to derive the lambda expression’s function type, and to check for expressions that are clearly disqualified from compatibility.
We do not attempt to produce bounds on inference variables that appear in the target function type’s throws
clause. This is because exception containment is not part of compatibility (15.27.3) - in particular, it must not influence method applicability (18.5.1). However, we do get bounds on these variables later, because invocation type inference (18.5.2) produces exception containment constraint formulas ([18.2.5]).
Note that if the target type is an inference variable, or if the target type’s parameter types contain inference variables, we produce false. During invocation type inference (18.5.2), extra substitutions are performed in order to instantiate these inference variables, thus avoiding this scenario. (In other words, reduction will, in practice, never be “invoked” with a target type of one of these forms.)
Finally, note that the result expressions of a lambda expression are required by 15.27.3 to be compatible in an assignment context with the target type’s return type, R. If R is a proper type, such as Byte
derived from Function<
α,Byte``>
, then assignability is easy enough to test, and reduction does so above. If R is not a proper type, such as α derived from Function<
String,α>
, then we make the simplifying assumption above that loose invocation compatibility will be sufficient. The difference between assignment compatibility and loose invocation compatibility is that only assignment allows narrowing of constant expressions, such as Byte b = 100;
. Consequently, our simplifying assumption is not completeness-preserving: given target return type α and an integer literal result expression 100
, it is conceivable that α could be instantiated to Byte
, but reduction will not in fact produce such a bound.
A constraint formula of the form ‹MethodReference → T›, where T mentions at least one inference variable, is reduced as follows:
If T is not a functional interface type, or if T is a functional interface type that does not have a function type (9.9), the constraint reduces to false.
Otherwise, if there does not exist a potentially applicable method for the method reference when targeting T, the constraint reduces to false.
Otherwise, if the method reference is exact (15.13.1), then let P1, …, Pn be the parameter types of the function type of T, and let F1, …, Fk be the parameter types of the potentially applicable method. The constraint reduces to a new set of constraints, as follows:
In the special case where n = k+1, the parameter of type P1 is to act as the target reference of the invocation. The method reference expression necessarily has the form ReferenceType ::
[TypeArguments] Identifier. The constraint reduces to ‹P1 <:
ReferenceType› and, for all i (2 ≤ i ≤ n), ‹Pi → Fi-1›.
In all other cases, n = k, and the constraint reduces to, for all i (1 ≤ i ≤ n), ‹Pi → Fi›.
If the function type’s result is not void
, let R be its return type. Then, if the result of the potentially applicable compile-time declaration is void
, the constraint reduces to false. Otherwise, the constraint reduces to ‹R’ → R›, where R’ is the result of applying capture conversion (5.1.10) to the return type of the potentially applicable compile-time declaration.
Otherwise, the method reference is inexact, and:
If one or more of the function type’s parameter types is not a proper type, the constraint reduces to false.
This condition never arises in practice, due to the handling of inexact method references in 18.5.1 and the substitution applied to the target type in 18.5.2.
Otherwise, a search for a compile-time declaration is performed, as specified in 15.13.1. If there is no compile-time declaration for the method reference, the constraint reduces to false. Otherwise, there is a compile-time declaration, and:
If the result of the function type is void
, the constraint reduces to true.
Otherwise, if the method reference expression elides TypeArguments, and the compile-time declaration is a generic method, and the return type of the compile-time declaration mentions at least one of the method’s type parameters, then the constraint reduces to the bound set B3 which would be used to determine the method reference’s invocation type when targeting the return type of the function type, as defined in 18.5.2. B3 may contain new inference variables, as well as dependencies between these new variables and the inference variables in T.
Otherwise, let R be the return type of the function type, and let R’ be the result of applying capture conversion (5.1.10) to the return type of the invocation type (15.12.2.6) of the compile-time declaration. If R’ is void
, the constraint reduces to false; otherwise, the constraint reduces to ‹R’ → R›.
The strategy used to determine a return type for a generic referenced method follows the same pattern as for generic method invocations (18.2.1). This may involve “lifting” bounds into the outer context and inferring dependencies between the two sets of inference variables.
Given a method invocation that provides no explicit type arguments, and a corresponding most specific applicable generic method m
, the process to infer the invocation type (15.12.2.6) of the chosen method is as follows:
Let θ be the substitution [
P1:=α1, …, Pp:=αp]
defined in 18.5.1 to replace the type parameters of m
with inference variables.
Let B2 be the bound set produced by reduction in order to demonstrate that m
is applicable in 18.5.1. (While it was necessary in 18.5.1 to demonstrate that the inference variables in B2 could be resolved, in order to establish applicability, the instantiations produced by this resolution step are not considered part of B2.)
If the invocation is not a poly expression, let the bound set B3 be the same as B2.
If the invocation is a poly expression, let the bound set B3 be derived from B2 as follows. Let R be the return type of m
, let T be the invocation’s target type, and then:
If unchecked conversion was necessary for the method to be applicable during constraint set reduction in 18.5.1, the constraint formula ‹|R| → T› is reduced and incorporated with B2.
Otherwise, if R θ is a parameterized type, G<
A1, …, An>
, and one of A1, …, An is a wildcard, then, for fresh inference variables β1, …, βn, the constraint formula ‹G<
β1, …, βn>
→ T› is reduced and incorporated, along with the bound G<
β1, …, βn>
= capture(G<
A1, …, An>
), with B2.
Otherwise, if R θ is an inference variable α, and one of the following is true:
T is a reference type, but is not a wildcard-parameterized type, and either i) B2 contains a bound of one of the forms α = S or S <:
α, where S is a wildcard-parameterized type, or ii) B2 contains two bounds of the forms S1 <:
α and S2 <:
α, where S1 and S2 have supertypes that are two different parameterizations of the same generic class or interface.
T is a parameterization of a generic class or interface, G, and B2 contains a bound of one of the forms α = S or S <:
α, where there exists no type of the form G<
…>
that is a supertype of S, but the raw type |G<
…>
| is a supertype of S.
T is a primitive type, and one of the primitive wrapper classes mentioned in 5.1.7 is an instantiation, upper bound, or lower bound for α in B2.
then α is resolved in B2, and where the capture of the resulting instantiation of α is U, the constraint formula ‹U → T› is reduced and incorporated with B2.
Otherwise, the constraint formula ‹R θ → T› is reduced and incorporated with B2.
A set of constraint formulas, C, is constructed as follows.
Let e1
, …, ek
be the actual argument expressions of the invocation. If m
is applicable by strict or loose invocation, let F1, …, Fk be the formal parameter types of m
; if m
is applicable by variable arity invocation, let F1, …, Fk the first k variable arity parameter types of m
(15.12.2.4). Then:
For all i (1 ≤ i ≤ k), if ei
is not pertinent to applicability, C contains ‹ei
→ Fi θ›.
For all i (1 ≤ i ≤ k), additional constraints may be included, depending on the form of ei
:
If ei
is a LambdaExpression, C contains ‹LambdaExpression →throws Fi θ›.
In addition, the lambda body is searched for additional constraints:
For a block lambda body, the search is applied recursively to each result expression.
For a poly class instance creation expression (15.9) or a poly method invocation expression (15.12), C contains all the constraint formulas that would appear in the set C generated by 18.5.2 when inferring the poly expression’s invocation type.
For a parenthesized expression, the search is applied recursively to the contained expression.
For a conditional expression, the search is applied recursively to the second and third operands.
For a switch
expression, the search is applied recursively to each of its result expressions.
For a lambda expression, the search is applied recursively to the lambda body.
If ei
is a MethodReference, C contains ‹MethodReference →throws Fi θ›.
If ei
is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12), C contains all the constraint formulas that would appear in the set C generated by 18.5.2 when inferring the poly expression’s invocation type.
If ei
is a parenthesized expression, these rules are applied recursively to the contained expression.
If ei
is a conditional expression, these rules are applied recursively to the second and third operands.
If ei
is a switch
expression, these rules are applied recursively to each of its result expressions.
While C is not empty, the following process is repeated, starting with the bound set B3 and accumulating new bounds into a “current” bound set, ultimately producing a new bound set, B4:
A subset of constraints is selected in C, satisfying the property that, for each constraint, no input variable can influence an output variable of another constraint in C. The terms input variable and output variable are defined below. An inference variable α can influence an inference variable β if α depends on the resolution of β (18.4), or vice versa; or if there exists a third inference variable γ such that α can influence γ and γ can influence β.
If this subset is empty, then there is a cycle (or cycles) in the graph of dependencies between constraints. In this case, all constraints are considered that participate in a dependency cycle (or cycles) and do not depend on any constraints outside of the cycle (or cycles). A single constraint is selected from the considered constraints, as follows:
If any of the considered constraints have the form ‹Expression → T›, then the selected constraint is the considered constraint of this form that contains the expression to the left (3.5) of the expression of every other considered constraint of this form.
If no considered constraint has the form ‹Expression → T›, then the selected constraint is the considered constraint that contains the expression to the left of the expression of every other considered constraint.
The selected constraint(s) are removed from C.
The input variables α1, …, αm of all the selected constraint(s) are resolved.
Where T1, …, Tm are the instantiations of α1, …, αm, the substitution [
α1:=T1, …, αm:=Tm]
is applied to every constraint.
The constraint(s) resulting from substitution are reduced and incorporated with the current bound set.
Finally, if B4 does not contain the bound false, the inference variables in B4 are resolved.
If resolution succeeds with instantiations T1, …, Tp for inference variables α1, …, αp, let θ’ be the substitution [
P1:=T1, …, Pp:=Tp]
. Then:
If unchecked conversion was necessary for the method to be applicable during constraint set reduction in 18.5.1, then the parameter types of the invocation type of m
are obtained by applying θ’ to the parameter types of m
’s type, and the return type and thrown types of the invocation type of m
are given by the erasure of the return type and thrown types of m
’s type.
If unchecked conversion was not necessary for the method to be applicable, then the invocation type of m
is obtained by applying θ’ to the type of m
.
If B4 contains the bound false, or if resolution fails, then a compile-time error occurs.
Invocation type inference may require carefully sequencing the reduction of constraint formulas of the forms ‹Expression → T›, ‹LambdaExpression →throws T›, and ‹MethodReference →throws T›. To facilitate this sequencing, the input variables of these constraints are defined as follows:
For ‹LambdaExpression → T›:
If T is an inference variable, it is the (only) input variable.
If T is a functional interface type, and a function type can be derived from T (15.27.3), then the input variables include i) if the lambda expression is implicitly typed, the inference variables mentioned by the function type’s parameter types; and ii) if the function type’s return type, R, is not void
, then for each result expression e
in the lambda body (or for the body itself if it is an expression), the input variables of ‹e
→ R›.
Otherwise, there are no input variables.
For ‹LambdaExpression →throws T›:
If T is an inference variable, it is the (only) input variable.
If T is a functional interface type, and a function type can be derived, as described in 15.27.3, the input variables include i) if the lambda expression is implicitly typed, the inference variables mentioned by the function type’s parameter types; and ii) the inference variables mentioned by the function type’s return type.
Otherwise, there are no input variables.
For ‹MethodReference → T›:
If T is an inference variable, it is the (only) input variable.
If T is a functional interface type with a function type, and if the method reference is inexact (15.13.1), the input variables are the inference variables mentioned by the function type’s parameter types.
Otherwise, there are no input variables.
For ‹MethodReference →throws T›:
If T is an inference variable, it is the (only) input variable.
If T is a functional interface type with a function type, and if the method reference is inexact (15.13.1), the input variables are the inference variables mentioned by the function type’s parameter types and the function type’s return type.
Otherwise, there are no input variables.
For ‹Expression → T›, if Expression is a parenthesized expression:
Where the contained expression of Expression is Expression‘, the input variables are the input variables of ‹Expression’ → T›.
For ‹ConditionalExpression → T›:
Where the conditional expression has the form e1
?
e2
:
e3
, the input variables are the input variables of ‹e2
→ T› and ‹e3
→ T›.
For ‹SwitchExpression → T›:
The input variables are the input variables of ‹ei
→ T›, where ei
are the result expressions of the switch
expression..
For all other constraint formulas, there are no input variables.
The output variables of these constraints are all inference variables mentioned by the type on the right-hand side of the constraint, T, that are not input variables.
It is important to note that two “rounds” of inference are involved in finding the type of a method invocation. This is necessary to allow a target type to influence the type of the invocation without allowing it to influence the choice of an applicable method. The first round produces a bound set and tests that a resolution exists, but does not commit to that resolution. The second round reduces additional constraints and then performs a second resolution, this time “for real”.
Consider the example from the previous section:
List<Number> ln = Arrays.asList(1, 2.0);
The most specific applicable method was identified as:
public static <T> List<T> asList(T... a)
In order to complete type-checking of the method invocation, we must determine whether it is compatible with its target type, List<
Number>
.
The bound set used to demonstrate applicability in the previous section, B2, was:
{ α <:
Object
, Integer
<:
α, Double
<:
α }
The new constraint formula set is as follows:
{ ‹List<
α>
→ List<
Number>
› }
This compatibility constraint produces an equality bound for α, which is included in the new bound set, B3:
{ α <:
Object
, Integer
<:
α, Double
<:
α, α = Number
}
These bounds are trivially resolved:
α = Number
Finally, we perform a substitution on the declared return type of asList
to determine that the method invocation has type List<
Number>
; clearly, this is compatible with the target type.
This inference strategy is different than the Java SE 7 Edition of The Java® Language Specification, which would have instantiated α based on its lower bounds (before even considering the invocation’s target type), as we did in the previous section. This would result in a type error, since the resulting type is not a subtype of List<
Number>
.
Under various special circumstances, based on the bounds appearing in B2, we eagerly resolve an inference variable that appears as the return type of the invocation. This is to avoid unfortunate situations in which the usual constraint, ‹R θ → T›, is not completeness-preserving. It is, unfortunately, possible that by eagerly resolving the variable, we are unable to make use of bounds that would be inferred later. It is also possible that, in some cases, bounds that will later be inferred from the invocation arguments (such as implicitly typed lambda expressions) would have caused a different outcome if they had been present in B2. Despite these limitations, the strategy allows for reasonable outcomes in typical use cases, and is backwards compatible with the algorithm in the Java SE 7 Edition of The Java® Language Specification.
When testing that one applicable method is more specific than another (15.12.2.5), where the second method is generic, it is necessary to test whether some instantiation of the second method’s type parameters can be inferred to make the first method more specific than the second.
Let m1
be the first method and m2
be the second method. Where m2
has type parameters P1, …, Pp, let α1, …, αp be inference variables, and let θ be the substitution [
P1:=α1, …, Pp:=αp]
.
Let e1
, …, ek
be the argument expressions of the corresponding invocation. Then:
If m1
and m2
are applicable by strict or loose invocation (15.12.2.2, 15.12.2.3), then let S1, …, Sk be the formal parameter types of m1
, and let T1, …, Tk be the result of θ applied to the formal parameter types of m2
.
If m1
and m2
are applicable by variable arity invocation (15.12.2.4), then let S1, …, Sk be the first k variable arity parameter types of m1
, and let T1, …, Tk be the result of θ applied to the first k variable arity parameter types of m2
.
Note that no substitution is applied to S1, …, Sk; even if m1
is generic, the type parameters of m1
are treated as type variables, not inference variables.
The process to determine if m1
is more specific than m2
is as follows:
First, an initial bound set, B, is constructed from the declared bounds of P1, …, Pp, as specified in 18.1.3.
Second, for all i (1 ≤ i ≤ k), a set of constraint formulas or bounds is generated.
If Ti is a proper type, the result is true if Si is more specific than Ti for ei
(15.12.2.5), and false otherwise. (Note that Si is always a proper type.)
Otherwise, if Ti is not a functional interface type, the constraint formula ‹Si <:
Ti› is generated.
Otherwise, Ti is a parameterization of a functional interface, I. It must be determined whether Si satisfies the following five conditions:
Si is a functional interface type.
Si is not a superinterface of I, nor a parameterization of a superinterface of I.
Si is not a subinterface of I, nor a parameterization of a subinterface of I.
If Si is an intersection type, at least one element of the intersection is not a superinterface of I, nor a parameterization of a superinterface of I.
If Si is an intersection type, no element of the intersection is a subinterface of I, nor a parameterization of a subinterface of I.
If all five conditions are true, then the following constraint formulas or bounds are generated (where U1 … Uk and R1 are the parameter types and return type of the function type of the capture of Si, and V1 … Vk and R2 are the parameter types and return type of the function type of Ti):
If ei
is an explicitly typed lambda expression:
For all j (1 ≤ j ≤ k), ‹Uj = Vj›.
If R2 is void
, true.
Otherwise, if R1 and R2 are functional interface types, and neither interface is a subinterface of the other, and ei
has at least one result expression, then these rules are applied recursively to R1 and R2, for each result expression in ei
.
Otherwise, if R1 is a primitive type and R2 is not, and ei
has at least one result expression, and each result expression of ei
is a standalone expression (15.2) of a primitive type, true.
Otherwise, if R2 is a primitive type and R1 is not, and ei
has at least one result expression, and each result expression of ei
is either a standalone expression of a reference type or a poly expression, true.
Otherwise, ‹R1 <:
R2›.
If ei
is an exact method reference:
For all j (1 ≤ j ≤ k), ‹Uj = Vj›.
If R2 is void
, true.
Otherwise, if R1 is a primitive type and R2 is not, and the compile-time declaration for ei
has a primitive return type, true.
Otherwise if R2 is a primitive type and R1 is not, and the compile-time declaration for ei
has a reference return type, true.
Otherwise, ‹R1 <:
R2›.
If ei
is a parenthesized expression, these rules are applied recursively to the contained expression.
If ei
is a conditional expression, these rules are applied recursively to each of the second and third operands.
If ei
is a switch
expression, these rules are applied recursively to each of its result expressions.
Otherwise, false.
If the five constraints on Si are not satisfied, the constraint formula ‹Si <:
Ti› is generated instead.
Third, if m2
is applicable by variable arity invocation and has k+1 parameters, then where Sk+1 is the k+1’th variable arity parameter type of m1
and Tk+1 is the result of θ applied to the k+1’th variable arity parameter type of m2
, the constraint ‹Sk+1 <:
Tk+1› is generated.
Fourth, the generated bounds and constraint formulas are reduced and incorporated with B to produce a bound set B’.
If B’ does not contain the bound false, and resolution of all the inference variables in B’ succeeds, then m1
is more specific than m2
.
Otherwise, m1
is not more specific than m2
.
Copyright © 2018 Oracle America, Inc. 4150 Network Circle, Santa Clara, California 95054, U.S.A. All rights reserved.
The Specification is protected by copyright and the information described therein may be protected by one or more U.S. patents, foreign patents, or pending applications. Except as provided under the following license, no part of the Specification may be reproduced in any form by any means without the prior written authorization of Oracle America, Inc. (“Oracle”) and its licensors, if any. Any use of the Specification and the information described therein will be governed by the terms and conditions of this Agreement.
Subject to the terms and conditions of this license, including your compliance with Paragraphs 1 and 2 below, Oracle hereby grants you a fully-paid, non-exclusive, non-transferable, limited license (without the right to sublicense) under Oracle’s intellectual property rights to:
Review the Specification for the purposes of evaluation. This includes: (i) developing implementations of the Specification for your internal, non-commercial use; (ii) discussing the Specification with any third party; and (iii) excerpting brief portions of the Specification in oral or written communications which discuss the Specification provided that such excerpts do not in the aggregate constitute a significant portion of the Technology.
Distribute implementations of the Specification to third parties for their testing and evaluation use, provided that any such implementation:
does not modify, subset, superset or otherwise extend the Licensor Name Space, or include any public or protected packages, classes, Java interfaces, fields or methods within the Licensor Name Space other than those required/authorized by the Specification or Specifications being implemented;
is clearly and prominently marked with the word “UNTESTED” or “EARLY ACCESS” or “INCOMPATIBLE” or “UNSTABLE” or “BETA” in any list of available builds and in proximity to every link initiating its download, where the list or link is under Licensee’s control; and
includes the following notice: “This is an implementation of an early-draft specification developed under the Java Community Process (JCP) and is made available for testing and evaluation purposes only. The code is not compatible with any specification of the JCP.”
The grant set forth above concerning your distribution of implementations of the specification is contingent upon your agreement to terminate development and distribution of your “early draft” implementation as soon as feasible following final completion of the specification. If you fail to do so, the foregoing grant shall be considered null and void.
No provision of this Agreement shall be understood to restrict your ability to make and distribute to third parties applications written to the Specification.
Other than this limited license, you acquire no right, title or interest in or to the Specification or any other Oracle intellectual property, and the Specification may only be used in accordance with the license terms set forth herein. This license will expire on the earlier of: (a) two (2) years from the date of Release listed above; (b) the date on which the final version of the Specification is publicly released; or (c) the date on which the Java Specification Request (JSR) to which the Specification corresponds is withdrawn. In addition, this license will terminate immediately without notice from Oracle if you fail to comply with any provision of this license. Upon termination, you must cease use of or destroy the Specification.
“Licensor Name Space” means the public class or interface declarations whose names begin with “java”, “javax”, “com.oracle” or their equivalents in any subsequent naming convention adopted by Oracle through the Java Community Process, or any recognized successors or replacements thereof.
No right, title, or interest in or to any trademarks, service marks, or trade names of Oracle or Oracle’s licensors is granted hereunder. Oracle, the Oracle logo, Java are trademarks or registered trademarks of Oracle USA, Inc. in the U.S. and other countries.
THE SPECIFICATION IS PROVIDED “AS IS” AND IS EXPERIMENTAL AND MAY CONTAIN DEFECTS OR DEFICIENCIES WHICH CANNOT OR WILL NOT BE CORRECTED BY ORACLE. ORACLE MAKES NO REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT THAT THE CONTENTS OF THE SPECIFICATION ARE SUITABLE FOR ANY PURPOSE OR THAT ANY PRACTICE OR IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADE SECRETS OR OTHER RIGHTS. This document does not represent any commitment to release or implement any portion of the Specification in any product.
THE SPECIFICATION COULD INCLUDE TECHNICAL INACCURACIES OR TYPOGRAPHICAL ERRORS. CHANGES ARE PERIODICALLY ADDED TO THE INFORMATION THEREIN; THESE CHANGES WILL BE INCORPORATED INTO NEW VERSIONS OF THE SPECIFICATION, IF ANY. ORACLE MAY MAKE IMPROVEMENTS AND/OR CHANGES TO THE PRODUCT(S) AND/OR THE PROGRAM(S) DESCRIBED IN THE SPECIFICATION AT ANY TIME. Any use of such changes in the Specification will be governed by the then-current license for the applicable version of the Specification.
TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL ORACLE OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES, INCLUDING WITHOUT LIMITATION, LOST REVENUE, PROFITS OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO ANY FURNISHING, PRACTICING, MODIFYING OR ANY USE OF THE SPECIFICATION, EVEN IF ORACLE AND/OR ITS LICENSORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
You will hold Oracle (and its licensors) harmless from any claims based on your use of the Specification for any purposes other than the limited right of evaluation as described above, and from any claims that later versions or releases of any Specification furnished to you are incompatible with the Specification provided to you under this license.
If this Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government’s rights in the Software and accompanying documentation shall be only as set forth in this license; this is in accordance with 48 C.F.R. 227.7201 through 227.7202-4 (for Department of Defense (DoD) acquisitions) and with 48 C.F.R. 2.101 and 12.212 (for non-DoD acquisitions).
You may wish to report any ambiguities, inconsistencies or inaccuracies you may find in connection with your evaluation of the Specification (“Feedback”). To the extent that you provide Oracle with any Feedback, you hereby: (i) agree that such Feedback is provided on a non-proprietary and non-confidential basis, and (ii) grant Oracle a perpetual, non-exclusive, worldwide, fully paid-up, irrevocable license, with the right to sublicense through multiple levels of sublicensees, to incorporate, disclose, and use without limitation the Feedback for any purpose related to the Specification and future versions, implementations, and test suites thereof.
Any action related to this Agreement will be governed by California law and controlling U.S. federal law. The U.N. Convention for the International Sale of Goods and the choice of law rules of any jurisdiction will not apply.
The Specification is subject to U.S. export control laws and may be subject to export or import regulations in other countries. Licensee agrees to comply strictly with all such laws and regulations and acknowledges that it has the responsibility to obtain such licenses to export, re-export or import as may be required after delivery to Licensee.
This Agreement is the parties’ entire agreement relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, conditions, representations and warranties and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification to this Agreement will be binding, unless in writing and signed by an authorized representative of each party.