Table of Contents
if
Statementassert
Statementswitch
Statementwhile
Statementdo
Statementfor
Statementbreak
Statementcontinue
Statementreturn
Statementthrow
Statementsynchronized
Statementtry
statementThe sequence of execution of a program is controlled bystatements, which are executed for their effect and do not have values.
Some statementscontain other statements as part of their structure; such other statements are substatements of the statement. We say that statementS
immediately contains statementU
if there is no statementT
different fromS
andU
such thatS
containsT
andT
containsU
. In the same manner, some statements contain expressions (§15 (Expressions)) as part of their structure.
The first section of this chapter discusses the distinction between normal and abrupt completion of statements (§14.1). Most of the remaining sections explain the various kinds of statements, describing in detail both their normal behavior and any special treatment of abrupt completion.
Blocks are explained first (§14.2), followed by local class declarations (§14.3) and local variable declaration statements (§14.4).
Next a grammatical maneuver that sidesteps the familiar "dangling else" problem (§14.5) is explained.
The last section (§14.21) of this chapter addresses the requirement that every statement bereachable in a certain technical sense.
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 tocomplete normally. However, certain events may prevent a statement from completing normally:
Thebreak
(§14.15),continue
(§14.16), andreturn
(§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 explicitthrow
(§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 tocomplete abruptly.
An abrupt completion always has an associatedreason, which is one of the following:
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 athrow
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.
Ablock is a sequence of statements, local class declarations, and local variable declaration statements within braces.
A block is executed by executing each of the local variable declaration statements and other statements in order from first to last (left to right). If all of these block statements complete normally, then the block completes normally. If any of these block statements complete abruptly for any reason, then the block completes abruptly for the same reason.
Alocal class is a nested class (§8 (Classes)) that is not a member of any class and that has a name (§6.2,§6.7).
All local classes are inner classes (§8.1.3).
Every local class declaration statement is immediately contained by a block (§14.2). Local class declaration statements may be intermixed freely with other kinds of statements in the block.
It is a compile-time error if a local class declaration contains any of the access modifierspublic
,protected
, orprivate
(§6.6), or the modifierstatic
(§8.1.1).
The scope and shadowing of a local class declaration is specified in§6.3 and§6.4.
Example 14.3-1. Local Class Declarations
Here is an example that illustrates several aspects of the rules given above:
class Global { class Cyclic {} void foo() { new Cyclic(); // create a Global.Cyclic class Cyclic extends Cyclic {} // circular definition { class Local {} { class Local {} // compile-time error } class Local {} // compile-time error class AnotherLocal { void bar() { class Local {} // ok } } } class Local {} // ok, not in scope of prior Local }}
The first statement of methodfoo
creates an instance of the member classGlobal.Cyclic
rather than an instance of the local classCyclic
, because the statement appears prior to the scope of the local class declaration.
The fact that the scope of a local class declaration encompasses its whole declaration (not only its body) means that the definition of the local classCyclic
is indeed cyclic because it extends itself rather thanGlobal.Cyclic
. Consequently, the declaration of the local classCyclic
is rejected at compile time.
Since local class names cannot be redeclared within the same method (or constructor or initializer, as the case may be), the second and third declarations ofLocal
result in compile-time errors. However,Local
can be redeclared in the context of another, more deeply nested, class such asAnotherLocal
.
The final declaration ofLocal
is legal, since it occurs outside the scope of any prior declaration ofLocal
.
Alocal variable declaration statement declares one or more local variable names.
See§8.3 forUnannType. The following productions from§4.3,§8.4.1, and§8.3 are shown here for convenience:
Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.
Apart from local variable declaration statements, a local variable declaration can appear in the header of afor
statement (§14.14) ortry
-with-resources statement (§14.20.3). In these cases, it is executed in the same manner as if it were part of a local variable declaration statement.
The rules for annotation modifiers on a local variable declaration are specified in§9.7.4 and§9.7.5.
It is a compile-time error iffinal
appears more than once as a modifier for a local variable declaration.
Eachdeclarator in a local variable declaration declares one local variable, whose name is theIdentifier that appears in the declarator.
If the optional keywordfinal
appears at the start of the declaration, the variable being declared is a final variable (§4.12.4).
The declared type of a local variable is denoted byUnannType if no bracket pairs appear inUnannType andVariableDeclaratorId, and is specified by§10.2 otherwise.
A local variable of typefloat
always contains a value that is an element of the float value set (§4.2.3); similarly, a local variable of typedouble
always contains a value that is an element of the double value set. It is not permitted for a local variable of typefloat
to contain an element of the float-extended-exponent value set that is not also an element of the float value set, nor for a local variable of typedouble
to contain an element of the double-extended-exponent value set that is not also an element of the double value set.
The scope and shadowing of a local variable declaration is specified in§6.3 and§6.4.
A local variable declaration statement is an executable statement. Every time it is executed, the declarators are processed in order from left to right. If a declarator has an initializer, the initializer is evaluated and its value is assigned to the variable.
If a declarator does not have an initializer, then every reference to the variable must be preceded by execution of an assignment to the variable, or a compile-time error occurs by the rules of§16 (Definite Assignment).
Each initializer (except the first) is evaluated only if evaluation of the preceding initializer completes normally.
Execution of the local variable declaration completes normally only if evaluation of the last initializer completes normally.
If the local variable declaration contains no initializers, then executing it always completes normally.
There are many kinds of statements in the Java programming language. Most correspond to statements in the C and C++ languages, but some are unique.
As in C and C++, theif
statement of the Java programming language suffers from the so-called "danglingelse
problem," illustrated by this misleadingly formatted example:
if (door.isOpen()) if (resident.isVisible()) resident.greet("Hello!");else door.bell.ring(); // A "dangling else"
The problem is that both the outerif
statement and the innerif
statement might conceivably own theelse
clause. In this example, one might surmise that the programmer intended theelse
clause to belong to the outerif
statement.
The Java programming language, like C and C++ and many programming languages before them, arbitrarily decrees that anelse
clause belongs to the innermostif
to which it might possibly belong. This rule is captured by the following grammar:
The following productions from§14.9 are shown here for convenience:
Statements are thus grammatically divided into two categories: those that might end in anif
statement that has noelse
clause (a "shortif
statement") and those that definitely do not.
Only statements that definitely do not end in a shortif
statement may appear as an immediate substatement before the keywordelse
in anif
statement that does have anelse
clause.
This simple rule prevents the "danglingelse
" problem. The execution behavior of a statement with the "no shortif
" restriction is identical to the execution behavior of the same kind of statement without the "no shortif
" restriction; the distinction is drawn purely to resolve the syntactic difficulty.
Statements may havelabel prefixes.
TheIdentifier is declared to be the label of the immediately containedStatement.
Unlike C and C++, the Java programming language has nogoto
statement; identifier statement labels are used withbreak
orcontinue
statements (§14.15,§14.16) appearing anywhere within the labeled statement.
The scope of a label of a labeled statement is the immediately containedStatement.
It is a compile-time error if the name of a label of a labeled statement is used within the scope of the label as a label of another labeled statement.
There is no restriction against using the same identifier as a label and as the name of a package, class, interface, method, field, parameter, or local variable. Use of an identifier to label a statement does not obscure (§6.4.2) a package, class, interface, method, field, parameter, or local variable with the same name. Use of an identifier as a class, interface, method, field, local variable or as the parameter of an exception handler (§14.20) does not obscure a statement label with the same name.
A labeled statement is executed by executing the immediately containedStatement.
If the statement is labeled by anIdentifier and the containedStatement completes abruptly because of abreak
with the sameIdentifier, then the labeled statement completes normally. In all other cases of abrupt completion of theStatement, the labeled statement completes abruptly for the same reason.
Example 14.7-1. Labels and Identifiers
The following code was taken from a version of the classString
and its methodindexOf
, where the label was originally calledtest
. Changing the label to have the same name as the local variablei
does not obscure the label in the scope of the declaration ofi
. Thus, the code is valid.
class Test { char[] value; int offset, count; int indexOf(TestString str, int fromIndex) { char[] v1 = value, v2 = str.value; int max = offset + (count - str.count); int start = offset + ((fromIndex < 0) ? 0 : fromIndex); i: for (int i = start; i <= max; i++) { int n = str.count, j = i, k = str.offset; while (n-- != 0) { if (v1[j++] != v2[k++]) continue i; } return i - offset; } return -1; }}
The identifiermax
could also have been used as the statement label; the label would not obscure the local variablemax
within the labeled statement.
Certain kinds of expressions may be used as statements by following them with semicolons.
Anexpression statement is executed by evaluating the expression; if the expression has a value, the value is discarded.
Execution of the expression statement completes normally if and only if evaluation of the expression completes normally.
Unlike C and C++, the Java programming language allows only certain forms of expressions to be used as expression statements. For example, it is legal to use a method invocation expression (§15.12):
System.out.println("Hello world"); // OK
but it is not legal to use a parenthesized expression (§15.8.5):
(System.out.println("Hello world")); // illegal
Note that the Java programming language does not allow a "cast tovoid
" -void
is not a type - so the traditional C trick of writing an expression statement such as:
(void)... ; // incorrect!
does not work. On the other hand, the Java programming language allows all the most useful kinds of expressions in expression statements, and it does not require a method invocation used as an expression statement to invoke avoid
method, so such a trick is almost never needed. If a trick is needed, either an assignment statement (§15.26) or a local variable declaration statement (§14.4) can be used instead.
Theif
statement allows conditional execution of a statement or a conditional choice of two statements, executing one or the other but not both.
TheExpression must have typeboolean
orBoolean
, or a compile-time error occurs.
Anif
-then
statement is executed by first evaluating theExpression. If the result is of typeBoolean
, it is subject to unboxing conversion (§5.1.8).
If evaluation of theExpression or the subsequent unboxing conversion (if any) completes abruptly for some reason, theif
-then
statement completes abruptly for the same reason.
Otherwise, execution continues by making a choice based on the resulting value:
Anif
-then
-else
statement is executed by first evaluating theExpression. If the result is of typeBoolean
, it is subject to unboxing conversion (§5.1.8).
If evaluation of theExpression or the subsequent unboxing conversion (if any) completes abruptly for some reason, then theif
-then
-else
statement completes abruptly for the same reason.
Otherwise, execution continues by making a choice based on the resulting value:
If the value istrue
, then the first containedStatement (the one before theelse
keyword) is executed; theif
-then
-else
statement completes normally if and only if execution of that statement completes normally.
If the value isfalse
, then the second containedStatement (the one after theelse
keyword) is executed; theif
-then
-else
statement completes normally if and only if execution of that statement completes normally.
Anassertion is anassert
statement containing a boolean expression. An assertion is eitherenabled ordisabled. If an assertion is enabled, execution of the assertion causes evaluation of the boolean expression and an error is reported if the expression evaluates tofalse
. If the assertion is disabled, execution of the assertion has no effect whatsoever.
To ease the presentation, the firstExpression in both forms of theassert
statement is referred to asExpression1. In the second form of theassert
statement, the secondExpression is referred to asExpression2.
It is a compile-time error ifExpression1 does not have typeboolean
orBoolean
.
In the second form of theassert
statement, it is a compile-time error ifExpression2 is void (§15.1).
Anassert
statement that is executed after its class or interface has completed initialization is enabled if and only if the host system has determined that the top level class or interface that lexically contains theassert
statement enables assertions.
Whether a top level class or interface enables assertions is determined no later than the earliest of i) the initialization of the top level class or interface, and ii) the initialization of any class or interface nested in the top level class or interface. Whether a top level class or interface enables assertions cannot be changed after it has been determined.
Anassert
statement that is executed before its class or interface has completed initialization is enabled.
This rule is motivated by a case that demands special treatment. Recall that the assertion status of a class is set no later than the time it is initialized. It is possible, though generally not desirable, to execute methods or constructors prior to initialization. This can happen when a class hierarchy contains a circularity in its static initialization, as in the following example:
public class Foo { public static void main(String[] args) { Baz.testAsserts(); // Will execute after Baz is initialized. }}class Bar { static { Baz.testAsserts(); // Will execute before Baz is initialized! }}class Baz extends Bar { static void testAsserts() { boolean enabled = false; assert enabled = true; System.out.println("Asserts " + (enabled ? "enabled" : "disabled")); }}
InvokingBaz.testAsserts()
causesBaz
to be initialized. Before this can happen,Bar
must be initialized.Bar
's static initializer again invokesBaz.testAsserts()
. Because initialization ofBaz
is already in progress by the current thread, the second invocation executes immediately, thoughBaz
is not initialized (§12.4.2).
Because of the rule above, if the program above is executed without enabling assertions, it must print:
Asserts enabledAsserts disabled
A disabledassert
statement does nothing. In particular, neitherExpression1 norExpression2 (if it is present) are evaluated. Execution of a disabledassert
statement always completes normally.
An enabledassert
statement is executed by first evaluatingExpression1. If the result is of typeBoolean
, it is subject to unboxing conversion (§5.1.8).
If evaluation ofExpression1 or the subsequent unboxing conversion (if any) completes abruptly for some reason, theassert
statement completes abruptly for the same reason.
Otherwise, execution continues by making a choice based on the value ofExpression1:
Typically, assertion checking is enabled during program development and testing, and disabled for deployment, to improve performance.
Because assertions may be disabled, programs must not assume that the expressions contained in assertions will be evaluated. Thus, these boolean expressions should generally be free of side effects. Evaluating such a boolean expression should not affect any state that is visible after the evaluation is complete. It is not illegal for a boolean expression contained in an assertion to have a side effect, but it is generally inappropriate, as it could cause program behavior to vary depending on whether assertions were enabled or disabled.
In light of this, assertions should not be used for argument checking inpublic
methods. Argument checking is typically part of the contract of a method, and this contract must be upheld whether assertions are enabled or disabled.
A secondary problem with using assertions for argument checking is that erroneous arguments should result in an appropriate run-time exception (such asIllegalArgumentException
,ArrayIndexOutOfBoundsException
, orNullPointerException
). An assertion failure will not throw an appropriate exception. Again, it is not illegal to use assertions for argument checking onpublic
methods, but it is generally inappropriate. It is intended thatAssertionError
never be caught, but it is possible to do so, thus the rules fortry
statements should treat assertions appearing in atry
block similarly to the current treatment ofthrow
statements.
Theswitch
statement transfers control to one of several statements depending on the value of an expression.
The type of theExpression must bechar
,byte
,short
,int
,Character
,Byte
,Short
,Integer
,String
, or an enum type (§8.9), or a compile-time error occurs.
The body of aswitch
statement is known as aswitch block. Any statement immediately contained by the switch block may be labeled with one or moreswitch labels, which arecase
ordefault
labels. Everycase
label has acase
constant, which is either a constant expression or the name of an enum constant. Switch labels and theircase
constants are said to beassociated with theswitch
statement.
Given aswitch
statement, all of the following must be true or a compile-time error occurs:
Everycase
constant associated with theswitch
statement must be assignment compatible with the type of theswitch
statement'sExpression (§5.2).
If the type of theswitch
statement'sExpression is an enum type, then everycase
constant associated with theswitch
statement must be an enum constant of that type.
No two of thecase
constants associated with theswitch
statement have the same value.
At most onedefault
label is associated with theswitch
statement.
The prohibition against usingnull
as acase
constant prevents code being written that can never be executed. If theswitch
statement'sExpression 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 theExpression evaluates tonull
at run time. In the judgment of the designers of the Java programming language, this is a better outcome than silently skipping the entireswitch
statement or choosing to execute the statements (if any) after thedefault
label (if any).
A Java compiler is encouraged (but not required) to provide a warning if aswitch
on an enum-valued expression lacks adefault
label and lackscase
labels for one or more of the enum's constants. Such aswitch
will silently do nothing if the expression evaluates to one of the missing constants.
In C and C++ the body of aswitch
statement can be a statement and statements withcase
labels do not have to be immediately contained by that statement. Consider the simple loop:
for (i = 0; i < n; ++i) foo();
wheren
is known to be positive. A trick known asDuff'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.
When theswitch
statement is executed, first theExpression is evaluated. If theExpression evaluates tonull
, aNullPointerException
is thrown and the entireswitch
statement completes abruptly for that reason. Otherwise, if the result is of a reference type, it is subject to unboxing conversion (§5.1.8).
If evaluation of theExpression or the subsequent unboxing conversion (if any) completes abruptly for some reason, theswitch
statement completes abruptly for the same reason.
Otherwise, execution continues by comparing the value of theExpression with eachcase
constant, and there is a choice:
If one of thecase
constants is equal to the value of the expression, then we say that thecase
labelmatches. All statements after the matchingcase
label in theswitch
block, if any, are executed in sequence.
If all these statements complete normally, or if there are no statements after the matchingcase
label, then the entireswitch
statement completes normally.
If nocase
label matches but there is adefault
label, then all statements after thedefault
label in theswitch
block, if any, are executed in sequence.
If all these statements complete normally, or if there are no statements after thedefault
label, then the entireswitch
statement completes normally.
If nocase
label matches and there is nodefault
label, then no further action is taken and theswitch
statement completes normally.
If any statement immediately contained by theBlock body of theswitch
statement completes abruptly, it is handled as follows:
If execution of theStatement completes abruptly because of abreak
with no label, no further action is taken and theswitch
statement completes normally.
If execution of theStatement completes abruptly for any other reason, theswitch
statement completes abruptly for the same reason.
The case of abrupt completion because of abreak
with a label is handled by the general rule for labeled statements (§14.7).
Example 14.11-1. Fall-Through in theswitch
Statement
As in C and C++, execution of statements in aswitch
block "falls 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 aswitch
block in which the code for eachcase
falls through into the code for the nextcase
. As a result, the program prints:
manytoo manyone too many
If code is not to fall throughcase
tocase
in this manner, thenbreak
statements should be used, as in this example:
class TwoMany { static void howMany(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) { howMany(1); howMany(2); howMany(3); }}
This program prints:
onetwomany
Thewhile
statement executes anExpression and aStatement repeatedly until the value of theExpression isfalse
.
TheExpression must have typeboolean
orBoolean
, or a compile-time error occurs.
Awhile
statement is executed by first evaluating theExpression. If the result is of typeBoolean
, it is subject to unboxing conversion (§5.1.8).
If evaluation of theExpression or the subsequent unboxing conversion (if any) completes abruptly for some reason, thewhile
statement completes abruptly for the same reason.
Otherwise, execution continues by making a choice based on the resulting value:
If the value istrue
, then the containedStatement is executed. Then there is a choice:
If execution of theStatement completes normally, then the entirewhile
statement is executed again, beginning by re-evaluating theExpression.
If execution of theStatement completes abruptly, see§14.12.1.
If the (possibly unboxed) value of theExpression isfalse
, no further action is taken and thewhile
statement completes normally.
If the (possibly unboxed) value of theExpression isfalse
the first time it is evaluated, then theStatement is not executed.
Abrupt completion of the containedStatement is handled in the following manner:
If execution of theStatement completes abruptly because of abreak
with no label, no further action is taken and thewhile
statement completes normally.
If execution of theStatement completes abruptly because of acontinue
with no label, then the entirewhile
statement is executed again.
If execution of theStatement completes abruptly because of acontinue
with labelL
, then there is a choice:
If execution of theStatement completes abruptly for any other reason, thewhile
statement completes abruptly for the same reason.
The case of abrupt completion because of abreak
with a label is handled by the general rule for labeled statements (§14.7).
Thedo
statement executes aStatement and anExpression repeatedly until the value of theExpression isfalse
.
TheExpression must have typeboolean
orBoolean
, or a compile-time error occurs.
Ado
statement is executed by first executing theStatement. Then there is a choice:
If execution of theStatement completes normally, then theExpression is evaluated. If the result is of typeBoolean
, it is subject to unboxing conversion (§5.1.8).
If evaluation of theExpression or the subsequent unboxing conversion (if any) completes abruptly for some reason, thedo
statement completes abruptly for the same reason.
If execution of theStatement completes abruptly, see§14.13.1.
Executing ado
statement always executes the containedStatement at least once.
Abrupt completion of the containedStatement is handled in the following manner:
If execution of theStatement completes abruptly because of abreak
with no label, then no further action is taken and thedo
statement completes normally.
If execution of theStatement completes abruptly because of acontinue
with no label, then theExpression is evaluated. Then there is a choice based on the resulting value:
If execution of theStatement completes abruptly because of acontinue
with labelL
, then there is a choice:
If execution of theStatement completes abruptly for any other reason, thedo
statement completes abruptly for the same reason.
The case of abrupt completion because of abreak
with a label is handled by the general rule for labeled statements (§14.7).
Example 14.13-1. Thedo
Statement
The following code is one possible implementation of thetoHexString
method of classInteger
:
public static String toHexString(int i) { StringBuffer buf = new StringBuffer(8); do { buf.append(Character.forDigit(i & 0xF, 16)); i >>>= 4; } while (i != 0); return buf.reverse().toString();}
Because at least one digit must be generated, thedo
statement is an appropriate control structure.
Thefor
statement has two forms:
The basicfor
statement executes some initialization code, then executes anExpression, aStatement, and some update code repeatedly until the value of theExpression isfalse
.
TheExpression must have typeboolean
orBoolean
, or a compile-time error occurs.
The scope and shadowing of a local variable declared in theForInit part of a basicfor
statement is specified in§6.3 and§6.4.
Afor
statement is executed by first executing theForInit code:
If theForInit code is a list of statement expressions (§14.8), the expressions are evaluated in sequence from left to right; their values, if any, are discarded.
If evaluation of any expression completes abruptly for some reason, thefor
statement completes abruptly for the same reason; anyForInit statement expressions to the right of the one that completed abruptly are not evaluated.
If theForInit code is a local variable declaration (§14.4), it is executed as if it were a local variable declaration statement appearing in a block.
If execution of the local variable declaration completes abruptly for any reason, thefor
statement completes abruptly for the same reason.
Next, afor
iteration step is performed, as follows:
If theExpression is present, it is evaluated. If the result is of typeBoolean
, it is subject to unboxing conversion (§5.1.8).
If evaluation of theExpression or the subsequent unboxing conversion (if any) completes abruptly, thefor
statement completes abruptly for the same reason.
Otherwise, there is then a choice based on the presence or absence of theExpression and the resulting value if theExpression is present; see next bullet.
If theExpression is not present, or it is present and the value resulting from its evaluation (including any possible unboxing) istrue
, then the containedStatement is executed. Then there is a choice:
If execution of theStatement completes normally, then the following two steps are performed in sequence:
First, if theForUpdate part is present, the expressions are evaluated in sequence from left to right; their values, if any, are discarded. If evaluation of any expression completes abruptly for some reason, thefor
statement completes abruptly for the same reason; anyForUpdate statement expressions to the right of the one that completed abruptly are not evaluated.
If execution of theStatement completes abruptly, see§14.14.1.3.
If theExpression is present and the value resulting from its evaluation (including any possible unboxing) isfalse
, no further action is taken and thefor
statement completes normally.
If the (possibly unboxed) value of theExpression isfalse
the first time it is evaluated, then theStatement is not executed.
If theExpression is not present, then the only way afor
statement can complete normally is by use of abreak
statement.
Abrupt completion of the containedStatement is handled in the following manner:
If execution of theStatement completes abruptly because of abreak
with no label, no further action is taken and thefor
statement completes normally.
If execution of theStatement completes abruptly because of acontinue
with no label, then the following two steps are performed in sequence:
If execution of theStatement completes abruptly because of acontinue
with labelL
, then there is a choice:
If execution of theStatement completes abruptly for any other reason, thefor
statement completes abruptly for the same reason.
Note that the case of abrupt completion because of abreak
with a label is handled by the general rule for labeled statements (§14.7).
The enhancedfor
statement has the form:
See§8.3 forUnannType. The following productions from§4.3,§8.4.1, and§8.3 are shown here for convenience:
The type of theExpression must beIterable
or an array type (§10.1), or a compile-time error occurs.
The declared type of the local variable in the header of the enhancedfor
statement is denoted byUnannType if no bracket pairs appear inUnannType andVariableDeclaratorId, and is specified by§10.2 otherwise.
The scope and shadowing of the local variable declared in the header of an enhancedfor
statement is specified in§6.3 and§6.4.
The meaning of the enhancedfor
statement is given by translation into a basicfor
statement, as follows:
If the type ofExpression is a subtype ofIterable
, then the translation is as follows.
If the type ofExpression is a subtype ofIterable
<
X>
for some type argumentX, then letI be the typejava.util.Iterator
<
X>
; otherwise, letI be the raw typejava.util.Iterator
.
The enhancedfor
statement is equivalent to a basicfor
statement of the form:
for (I #i =Expression.iterator(); #i.hasNext(); ) {{VariableModifier} TargetType Identifier = (TargetType) #i.next();Statement}
#i
is an automatically generated identifier that is distinct from any other identifiers (automatically generated or otherwise) that are in scope (§6.3) at the point where the enhancedfor
statement occurs.
If the declared type of the local variable in the header of the enhancedfor
statement is a reference type, thenTargetType is that declared type; otherwise,TargetType is the upper bound of the capture conversion (§5.1.10) of the type argument ofI, orObject
ifI is raw.
For example, this code:
List<? extends Integer> l = ...for (float i : l) ...
will be translated to:
for (Iterator<Integer> #i = l.iterator(); #i.hasNext(); ) { float #i0 = (Integer)#i.next(); ...
Otherwise, theExpression necessarily has an array type,T[]
.
LetL1
...Lm
be the (possibly empty) sequence of labels immediately preceding the enhancedfor
statement.
The enhancedfor
statement is equivalent to a basicfor
statement of the form:
T[]
#a =Expression;L1
:L2
: ...Lm
:for (int #i = 0; #i < #a.length; #i++) {{VariableModifier} TargetType Identifier = #a[#i];Statement}
#a
and#i
are automatically generated identifiers that are distinct from any other identifiers (automatically generated or otherwise) that are in scope at the point where the enhancedfor
statement occurs.
TargetType is the declared type of the local variable in the header of the enhancedfor
statement.
Example 14.14-1. Enhancedfor
And Arrays
The following program, which calculates the sum of an integer array, shows how enhancedfor
works for arrays:
int sum(int[] a) { int sum = 0; for (int i : a) sum += i; return sum;}
Example 14.14-2. Enhancedfor
And Unboxing Conversion
The following program combines the enhancedfor
statement with auto-unboxing to translate a histogram into a frequency table:
Map<String, Integer> histogram = ...;double total = 0;for (int i : histogram.values()) total += i;for (Map.Entry<String, Integer> e : histogram.entrySet()) System.out.println(e.getKey() + " " + e.getValue() / total);}
Abreak
statement transfers control out of an enclosing statement.
Abreak
statement with no label attempts to transfer control to the innermost enclosingswitch
,while
,do
, orfor
statement of the immediately enclosing method or initializer; this statement, which is called thebreak target, then immediately completes normally.
To be precise, abreak
statement with no label always completes abruptly, the reason being abreak
with no label.
If noswitch
,while
,do
, orfor
statement in the immediately enclosing method, constructor, or initializer contains thebreak
statement, a compile-time error occurs.
Abreak
statement with labelIdentifier attempts to transfer control to the enclosing labeled statement (§14.7) that has the sameIdentifier as its label; this statement, which is called thebreak target, then immediately completes normally. In this case, the break target need not be aswitch
,while
,do
, orfor
statement.
To be precise, abreak
statement with labelIdentifier always completes abruptly, the reason being abreak
with labelIdentifier.
Abreak
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 withIdentifier as its label in the immediately enclosing method, constructor, initializer, or lambda body contains thebreak
statement, a compile-time error occurs.
It can be seen, then, that abreak
statement always completes abruptly.
The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are anytry
statements (§14.20) within the break target whosetry
blocks orcatch
clauses contain thebreak
statement, then anyfinally
clauses of thosetry
statements are executed, in order, innermost to outermost, before control is transferred to the break target. Abrupt completion of afinally
clause can disrupt the transfer of control initiated by abreak
statement.
Example 14.15-1. Thebreak
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 nodesP
andQ
, whereQ
may be the same asP
, there is at most one edge fromP
toQ
.
Nodes are represented by integers, and there is an edge from nodei
to nodeedges[
for everyi
][j
]i
andj
for which the array referenceedges[
does not throw ani
][j
]ArrayIndexOutOfBoundsException
.
The task of the methodloseEdges
, given integersi
andj
, is to construct a new graph by copying a given graph but omitting the edge from nodei
to nodej
, if any, and the edge from nodej
to nodei
, 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
andsearch
, and the use ofbreak
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 nodei
to nodej
, and the test for an edge from nodej
to nodei
.
Acontinue
statement may occur only in awhile
,do
, orfor
statement; statements of these three kinds are callediteration statements. Control passes to the loop-continuation point of an iteration statement.
Acontinue
statement with no label attempts to transfer control to the innermost enclosingwhile
,do
, orfor
statement of the immediately enclosing method, constructor, or initializer; this statement, which is called thecontinue target, then immediately ends the current iteration and begins a new one.
To be precise, such acontinue
statement always completes abruptly, the reason being acontinue
with no label.
If nowhile
,do
, orfor
statement of the immediately enclosing method, constructor, or initializer contains thecontinue
statement, a compile-time error occurs.
Acontinue
statement with labelIdentifier attempts to transfer control to the enclosing labeled statement (§14.7) that has the sameIdentifier as its label; that statement, which is called thecontinue target, then immediately ends the current iteration and begins a new one.
To be precise, acontinue
statement with labelIdentifier always completes abruptly, the reason being acontinue
with labelIdentifier.
The continue target must be awhile
,do
, orfor
statement, or a compile-time error occurs.
Acontinue
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 withIdentifier as its label in the immediately enclosing method, constructor, initializer, or lambda body contains thecontinue
statement, a compile-time error occurs.
It can be seen, then, that acontinue
statement always completes abruptly.
See the descriptions of thewhile
statement (§14.12),do
statement (§14.13), andfor
statement (§14.14) for a discussion of the handling of abrupt termination because ofcontinue
.
The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are anytry
statements (§14.20) within the continue target whosetry
blocks orcatch
clauses contain thecontinue
statement, then anyfinally
clauses of thosetry
statements are executed, in order, innermost to outermost, before control is transferred to the continue target. Abrupt completion of afinally
clause can disrupt the transfer of control initiated by acontinue
statement.
Example 14.16-1. Thecontinue
Statement
In theGraph
class in§14.15, one of thebreak
statements is used to finish execution of the entire body of the outermostfor
loop. This break can be replaced by acontinue
if thefor
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.
Areturn
statement returns control to the invoker of a method (§8.4,§15.12) or constructor (§8.8,§15.9).
Areturn
statement iscontained in the innermost constructor, method, initializer, or lambda expression whose body encloses thereturn
statement.
It is a compile-time error if areturn
statement is contained in an instance initializer or a static initializer (§8.6,§8.7).
Areturn
statement with noExpression must be contained in one of the following, or a compile-time error occurs:
Areturn
statement with noExpression attempts to transfer control to the invoker of the method, constructor, or lambda body that contains it. To be precise, areturn
statement with noExpression always completes abruptly, the reason being a return with no value.
Areturn
statement with anExpression must be contained in one of the following, or a compile-time error occurs:
TheExpression must denote a variable or a value, or a compile-time error occurs.
When areturn
statement with anExpression appears in a method declaration, theExpression must be assignable (§5.2) to the declared return type of the method, or a compile-time error occurs.
Areturn
statement with anExpression attempts to transfer control to the invoker of the method or lambda body that contains it; the value of theExpression becomes the value of the method invocation. More precisely, execution of such areturn
statement first evaluates theExpression. If the evaluation of theExpression completes abruptly for some reason, then thereturn
statement completes abruptly for that reason. If evaluation of theExpression completes normally, producing a valueV
, then thereturn
statement completes abruptly, the reason being a return with valueV
.
If the expression is of typefloat
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 typedouble
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 areturn
statement always completes abruptly.
The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are anytry
statements (§14.20) within the method or constructor whosetry
blocks orcatch
clauses contain thereturn
statement, then anyfinally
clauses of thosetry
statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of afinally
clause can disrupt the transfer of control initiated by areturn
statement.
Athrow
statement causes an exception (§11 (Exceptions)) to be thrown. The result is an immediate transfer of control (§11.3) that may exit multiple statements and multiple constructor, instance initializer, static initializer and field initializer evaluations, and method invocations until atry
statement (§14.20) is found that catches the thrown value. If no suchtry
statement is found, then execution of the thread (§17 (Threads and Locks)) that executed thethrow
is terminated (§11.3) after invocation of theuncaughtException
method for the thread group to which the thread belongs.
TheExpression in athrow
statement must either denote a variable or value of a reference type which is assignable (§5.2) to the typeThrowable
, or denote the null reference, or a compile-time error occurs.
The reference type of theExpression will always be a class type (since no interface types are assignable toThrowable
) which is not parameterized (since a subclass ofThrowable
cannot be generic (§8.1.2)).
At least one of the following three conditions must be true, or a compile-time error occurs:
The type of theExpression is an unchecked exception class (§11.1.1) or the null type (§4.1).
Thethrow
statement is contained in thetry
block of atry
statement (§14.20) and it is not the case that thetry
statement can throw an exception of the type of theExpression. (In this case we say the thrown value iscaught by thetry
statement.)
Thethrow
statement is contained in a method or constructor declaration and the type of theExpression is assignable (§5.2) to at least one type listed in thethrows
clause (§8.4.6,§8.8.5) of the declaration.
The exception types that athrow
statement can throw are specified in§11.2.2.
Athrow
statement first evaluates theExpression. Then:
If evaluation of theExpression completes abruptly for some reason, then thethrow
completes abruptly for that reason.
If evaluation of theExpression completes normally, producing a non-null
valueV
, then thethrow
statement completes abruptly, the reason being athrow
with valueV
.
If evaluation of theExpression completes normally, producing anull
value, then an instanceV'
of classNullPointerException
is created and thrown instead ofnull
. Thethrow
statement then completes abruptly, the reason being athrow
with valueV'
.
It can be seen, then, that athrow
statement always completes abruptly.
If there are any enclosingtry
statements (§14.20) whosetry
blocks contain thethrow
statement, then anyfinally
clauses of thosetry
statements are executed as control is transferred outward, until the thrown value is caught. Note that abrupt completion of afinally
clause can disrupt the transfer of control initiated by athrow
statement.
If athrow
statement is contained in a method declaration or a lambda expression, but its value is not caught by sometry
statement that contains it, then the invocation of the method completes abruptly because of thethrow
.
If athrow
statement is contained in a constructor declaration, but its value is not caught by sometry
statement that contains it, then the class instance creation expression that invoked the constructor will complete abruptly because of thethrow
(§15.9.4).
If athrow
statement is contained in a static initializer (§8.7), then a compile-time check (§11.2.3) ensures that either its value is always an unchecked exception or its value is always caught by sometry
statement that contains it. If at run time, despite this check, the value is not caught by sometry
statement that contains thethrow
statement, then the value is rethrown if it is an instance of classError
or one of its subclasses; otherwise, it is wrapped in anExceptionInInitializerError
object, which is then thrown (§12.4.2).
If athrow
statement is contained in an instance initializer (§8.6), then a compile-time check (§11.2.3) ensures that either its value is always an unchecked exception or its value is always caught by sometry
statement that contains it, or the type of the thrown exception (or one of its superclasses) occurs in thethrows
clause of every constructor of the class.
By convention, user-declared throwable types should usually be declared to be subclasses of classException
, which is a subclass of classThrowable
(§11.1.1).
Asynchronized
statement acquires a mutual-exclusion lock (§17.1) on behalf of the executing thread, executes a block, then releases the lock. While the executing thread owns the lock, no other thread may acquire the lock.
The type ofExpression must be a reference type, or a compile-time error occurs.
Asynchronized
statement is executed by first evaluating theExpression. Then:
If evaluation of theExpression completes abruptly for some reason, then thesynchronized
statement completes abruptly for the same reason.
Otherwise, if the value of theExpression isnull
, aNullPointerException
is thrown.
Otherwise, let the non-null
value of theExpression beV
. The executing thread locks the monitor associated withV
. Then theBlock is executed, and then there is a choice:
The locks acquired bysynchronized
statements are the same as the locks that are acquired implicitly bysynchronized
methods (§8.4.3.6). A single thread may acquire a lock more than once.
Acquiring the lock associated with an object does not in itself prevent other threads from accessing fields of the object or invoking un-synchronized
methods on the object. Other threads can also usesynchronized
methods or thesynchronized
statement in a conventional manner to achieve mutual exclusion.
Example 14.19-1. Thesynchronized
Statement
class Test { public static void main(String[] args) { Test t = new Test(); synchronized(t) { synchronized(t) { System.out.println("made it!"); } } }}
This program produces the output:
made it!
Note that this program would deadlock if a single thread were not permitted to lock a monitor more than once.
Atry
statement executes a block. If a value is thrown and thetry
statement has one or morecatch
clauses that can catch it, then control will be transferred to the first suchcatch
clause. If thetry
statement has afinally
clause, then another block of code is executed, no matter whether thetry
block completes normally or abruptly, and no matter whether acatch
clause is first given control.
See§8.3 forUnannClassType. The following productions from§4.3,§8.3, and§8.4.1 are shown here for convenience:
TheBlock immediately after the keywordtry
is called thetry
block of thetry
statement.
TheBlock immediately after the keywordfinally
is called thefinally
block of thetry
statement.
Atry
statement may havecatch
clauses, also calledexception handlers.
Acatch
clause declares exactly one parameter, which is called anexception parameter.
It is a compile-time error iffinal
appears more than once as a modifier for an exception parameter declaration.
The scope and shadowing of an exception parameter is specified in§6.3 and§6.4.
An exception parameter may denote its type as either a single class type or a union of two or more class types (calledalternatives). The alternatives of a union are syntactically separated by|
.
Acatch
clause whose exception parameter is denoted as a single class type is called auni-catch
clause.
Acatch
clause whose exception parameter is denoted as a union of types is called amulti-catch
clause.
Each class type used in the denotation of the type of an exception parameter must be the classThrowable
or a subclass ofThrowable
, or a compile-time error occurs.
It is a compile-time error if a type variable is used in the denotation of the type of an exception parameter.
It is a compile-time error if a union of types contains two alternativesDi andDj (i≠j) whereDi is a subtype ofDj (§4.10.2).
The declared type of an exception parameter that denotes its type with a single class type is that class type.
The declared type of an exception parameter that denotes its type as a union with alternativesD1|
D2|
...|
Dn is lub(D1,D2, ...,Dn).
An exception parameter of a multi-catch
clause is implicitly declaredfinal
if it is not explicitly declaredfinal
.
It is a compile-time error if an exception parameter that is implicitly or explicitly declaredfinal
is assigned to within the body of thecatch
clause.
An exception parameter of a uni-catch
clause is never implicitly declaredfinal
, but it may be explicitly declaredfinal
or be effectively final (§4.12.4).
An implicitlyfinal
exception parameter is final by virtue of its declaration, while an effectively final exception parameter is (as it were) final by virtue of how it is used. An exception parameter of a multi-catch
clause is implicitly declaredfinal
, so will never occur as the left-hand operand of an assignment operator, but it isnot considered effectively final.
If an exception parameter is effectively final (in a uni-catch
clause) or implicitly final (in a multi-catch
clause), then adding an explicitfinal
modifier to its declaration will not introduce any compile-time errors. On the other hand, if the exception parameter of a uni-catch
clause is explicitly declaredfinal
, then removing thefinal
modifier may introduce compile-time errors because the exception parameter, now considered to be effectively final, can no longer longer be referenced by anonymous and local class declarations in the body of thecatch
clause. If there are no compile-time errors, it is possible to further change the program so that the exception parameter is re-assigned in the body of thecatch
clause and thus will no longer be considered effectively final.
The exception types that atry
statement can throw are specified in§11.2.2.
The relationship of the exceptions thrown by thetry
block of atry
statement and caught by thecatch
clauses (if any) of thetry
statement is specified in§11.2.3.
Exception handlers are considered in left-to-right order: the earliest possiblecatch
clause accepts the exception, receiving as its argument the thrown exception object, as specified in§11.3.
A multi-catch
clause can be thought of as a sequence of uni-catch
clauses. That is, acatch
clause where the type of the exception parameter is denoted as a unionD1|
D2|
...|
Dn is equivalent to a sequence ofncatch
clauses where the types of the exception parameters are class typesD1,D2, ...,Dn respectively. In theBlock of each of thencatch
clauses, the declared type of the exception parameter is lub(D1,D2, ...,Dn). For example, the following code:
try { ... throws ReflectiveOperationException ...}catch (ClassNotFoundException | IllegalAccessException ex) { ... body ...}
is semantically equivalent to the following code:
try { ... throws ReflectiveOperationException ...}catch (final ClassNotFoundException ex1) { final ReflectiveOperationException ex = ex1; ... body ...}catch (final IllegalAccessException ex2) { final ReflectiveOperationException ex = ex2; ... body ...}
where the multi-catch
clause with two alternatives has been translated into two uni-catch
clauses, one for each alternative. A Java compiler is neither required nor recommended to compile a multi-catch
clause by duplicating code in this manner, since it is possible to represent the multi-catch
clause in aclass
file without duplication.
Afinally
clause ensures that thefinally
block is executed after thetry
block and anycatch
block that might be executed, no matter how control leaves thetry
block orcatch
block. Handling of thefinally
block is rather complex, so the two cases of atry
statement with and without afinally
block are described separately (§14.20.1,§14.20.2).
Atry
statement is permitted to omitcatch
clauses and afinally
clause if it is atry
-with-resources statement (§14.20.3).
Atry
statement without afinally
block is executed by first executing thetry
block. Then there is a choice:
If execution of thetry
block completes normally, then no further action is taken and thetry
statement completes normally.
If execution of thetry
block completes abruptly because of athrow
of a valueV
, then there is a choice:
If the run-time type ofV
is assignment compatible with (§5.2) a catchable exception class of anycatch
clause of thetry
statement, then the first (leftmost) suchcatch
clause is selected. The valueV
is assigned to the parameter of the selectedcatch
clause, and theBlock of thatcatch
clause is executed, and then there is a choice:
If the run-time type ofV
is not assignment compatible with a catchable exception class of anycatch
clause of thetry
statement, then thetry
statement completes abruptly because of athrow
of the valueV
.
If execution of thetry
block completes abruptly for any other reason, then thetry
statement completes abruptly for the same reason.
Example 14.20.1-1. Catching An Exception
class BlewIt extends Exception { BlewIt() { } BlewIt(String s) { super(s); }}class Test { static void blowUp() throws BlewIt { throw new BlewIt(); } public static void main(String[] args) { try { blowUp(); } catch (RuntimeException r) { System.out.println("Caught RuntimeException"); } catch (BlewIt b) { System.out.println("Caught BlewIt"); } }}
Here, the exceptionBlewIt
is thrown by the methodblowUp
. Thetry
-catch
statement in the body ofmain
has twocatch
clauses. The run-time type of the exception isBlewIt
which is not assignable to a variable of typeRuntimeException
, but is assignable to a variable of typeBlewIt
, so the output of the example is:
Caught BlewIt
Atry
statement with afinally
block is executed by first executing thetry
block. Then there is a choice:
If execution of thetry
block completes normally, then thefinally
block is executed, and then there is a choice:
If execution of thetry
block completes abruptly because of athrow
of a valueV
, then there is a choice:
If the run-time type ofV
is assignment compatible with a catchable exception class of anycatch
clause of thetry
statement, then the first (leftmost) suchcatch
clause is selected. The valueV
is assigned to the parameter of the selectedcatch
clause, and theBlock of thatcatch
clause is executed. Then there is a choice:
If the run-time type ofV
is not assignment compatible with a catchable exception class of anycatch
clause of thetry
statement, then thefinally
block is executed. Then there is a choice:
If execution of thetry
block completes abruptly for any other reasonR
, then thefinally
block is executed, and then there is a choice:
Example 14.20.2-1. Handling An Uncaught Exception Withfinally
class BlewIt extends Exception { BlewIt() { } BlewIt(String s) { super(s); }}class Test { static void blowUp() throws BlewIt { throw new NullPointerException(); } public static void main(String[] args) { try { blowUp(); } catch (BlewIt b) { System.out.println("Caught BlewIt"); } finally { System.out.println("Uncaught Exception"); } }}
This program produces the output:
Uncaught ExceptionException in thread "main" java.lang.NullPointerException at Test.blowUp(Test.java:7) at Test.main(Test.java:11)
TheNullPointerException
(which is a kind ofRuntimeException
) that is thrown by methodblowUp
is not caught by thetry
statement inmain
, because aNullPointerException
is not assignable to a variable of typeBlewIt
. This causes thefinally
clause to execute, after which the thread executingmain
, which is the only thread of the test program, terminates because of an uncaught exception, which typically results in printing the exception name and a simple backtrace. However, a backtrace is not required by this specification.
The problem with mandating a backtrace is that an exception can be created at one point in the program and thrown at a later one. It is prohibitively expensive to store a stack trace in an exception unless it is actually thrown (in which case the trace may be generated while unwinding the stack). Hence we do not mandate a back trace in every exception.
Atry
-with-resources statement is parameterized with variables (known asresources) that are initialized before execution of thetry
block and closed automatically, in the reverse order from which they were initialized, after execution of thetry
block.catch
clauses and afinally
clause are often unnecessary when resources are closed automatically.
See§8.3 forUnannType. The following productions from§4.3,§8.3, and§8.4.1 are shown here for convenience:
Aresource specification declares one or more local variables with initializer expressions to act asresources for thetry
statement.
It is a compile-time error for a resource specification to declare two variables with the same name.
It is a compile-time error iffinal
appears more than once as a modifier for each variable declared in a resource specification.
A variable declared in a resource specification is implicitly declaredfinal
(§4.12.4) if it is not explicitly declaredfinal
.
The type of a variable declared in a resource specification must be a subtype ofAutoCloseable
, or a compile-time error occurs.
The scope and shadowing of a variable declared in a resource specification is specified in§6.3 and§6.4.
Resources are initialized in left-to-right order. If a resource fails to initialize (that is, its initializer expression throws an exception), then all resources initialized so far by thetry
-with-resources statement are closed. If all resources initialize successfully, thetry
block executes as normal and then all non-null resources of thetry
-with-resources statement are closed.
Resources are closed in the reverse order from that in which they were initialized. A resource is closed only if it initialized to a non-null value. An exception from the closing of one resource does not prevent the closing of other resources. Such an exception issuppressed if an exception was thrown previously by an initializer, thetry
block, or the closing of a resource.
Atry
-with-resources statement whose resource specification declares multiple resources is treated as if it were multipletry
-with-resources statements, each of which has a resource specification that declares a single resource. When atry
-with-resources statement withn resources (n > 1) is translated, the result is atry
-with-resources statement withn-1 resources. Aftern such translations, there aren nestedtry
-catch
-finally
statements, and the overall translation is complete.
Atry
-with-resources statement with nocatch
clauses orfinally
clause is called abasictry
-with-resources statement.
The meaning of a basictry
-with-resources statement:
try ({VariableModifier} R Identifier =Expression ...)Block
is given by the following translation to a local variable declaration and atry
-catch
-finally
statement:
{ final{VariableModifierNoFinal} R Identifier =Expression; Throwable #primaryExc = null; tryResourceSpecification_tailBlock catch (Throwable #t) { #primaryExc = #t; throw #t; } finally { if (Identifier != null) { if (#primaryExc != null) { try {Identifier.close(); } catch (Throwable #suppressedExc) { #primaryExc.addSuppressed(#suppressedExc); } } else {Identifier.close(); } } }}
{VariableModifierNoFinal} is defined as{VariableModifier} withoutfinal
, if present.
#t
,#primaryExc
, and#suppressedExc
are automatically generated identifiers that are distinct from any other identifiers (automatically generated or otherwise) that are in scope at the point where thetry
-with-resources statement occurs.
If the resource specification declares one resource, thenResourceSpecification_tail is empty (and thetry
-catch
-finally
statement is not itself atry
-with-resources statement).
If the resource specification declaresn > 1 resources, thenResourceSpecification_tail consists of the 2nd, 3rd, ...,n'th resources declared in resource specification, in the same order (and thetry
-catch
-finally
statement is itself atry
-with-resources statement).
Reachability and definite assignment rules for the basictry
-with-resources statement are implicitly specified by the translation above.
In a basictry
-with-resources statement that manages a single resource:
If the initialization of the resource completes abruptly because of athrow
of a valueV
, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
.
If the initialization of the resource completes normally, and thetry
block completes abruptly because of athrow
of a valueV
, then:
If the automatic closing of the resource completes normally, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
.
If the automatic closing of the resource completes abruptly because of athrow
of a valueV2
, then thetry
-with-resources statement completes abruptly because of athrow
of valueV
withV2
added to the suppressed exception list ofV
.
If the initialization of the resource completes normally, and thetry
block completes normally, and the automatic closing of the resource completes abruptly because of athrow
of a valueV
, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
.
In a basictry
-with-resources statement that manages multiple resources:
If the initialization of a resource completes abruptly because of athrow
of a valueV
, then:
If the automatic closings of all successfully initialized resources (possibly zero) complete normally, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
.
If the automatic closings of all successfully initialized resources (possibly zero) complete abruptly because ofthrow
s of valuesV1
...Vn
, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
with any remaining valuesV1
...Vn
added to the suppressed exception list ofV
.
If the initialization of all resources completes normally, and thetry
block completes abruptly because of athrow
of a valueV
, then:
If the automatic closings of all initialized resources complete normally, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
.
If the automatic closings of one or more initialized resources complete abruptly because ofthrow
s of valuesV1
...Vn
, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
with any remaining valuesV1
...Vn
added to the suppressed exception list ofV
.
If the initialization of every resource completes normally, and thetry
block completes normally, then:
If one automatic closing of an initialized resource completes abruptly because of athrow
of valueV
, and all other automatic closings of initialized resources complete normally, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV
.
If more than one automatic closing of an initialized resource completes abruptly because ofthrow
s of valuesV1
...Vn
, then thetry
-with-resources statement completes abruptly because of athrow
of the valueV1
with any remaining valuesV2
...Vn
added to the suppressed exception list ofV1
(whereV1
is the exception from the rightmost resource failing to close andVn
is the exception from the leftmost resource failing to close).
Atry
-with-resources statement with at least onecatch
clause and/or afinally
clause is called anextendedtry
-with-resources statement.
The meaning of an extendedtry
-with-resources statement:
tryResourceSpecificationBlock[Catches][Finally]
is given by the following translation to a basictry
-with-resources statement nested inside atry
-catch
ortry
-finally
ortry
-catch
-finally
statement:
try { tryResourceSpecification Block}[Catches][Finally]
The effect of the translation is to put the resource specification "inside" thetry
statement. This allows acatch
clause of an extendedtry
-with-resources statement to catch an exception due to the automatic initialization or closing of any resource.
Furthermore, all resources will have been closed (or attempted to be closed) by the time thefinally
block is executed, in keeping with the intent of thefinally
keyword.
It is a compile-time error if a statement cannot be executed because it isunreachable.
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 ofwhile
,do
, andfor
statements whose condition expression has the constant valuetrue
, 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 ofn
is known at compile time and in principle it can be known at compile time that the assignment tok
can never be executed.
The rules in this section define two technical terms:
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 reachablebreak
statementexits a statement if, within the break target, either there are notry
statements whosetry
blocks contain thebreak
statement, or there aretry
statements whosetry
blocks contain thebreak
statement and allfinally
clauses of thosetry
statements can complete normally.
This definition is based on the logic around "attempts to transfer control" in§14.15.
Acontinue
statementcontinues ado
statement if, within thedo
statement, either there are notry
statements whosetry
blocks contain thecontinue
statement, or there aretry
statements whosetry
blocks contain thecontinue
statement and allfinally
clauses of thosetry
statements can complete normally.
The block that is the body of a constructor, method, instance initializer, or static initializer 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 statementS
in a non-empty block that is not a switch block is reachable iff the statement precedingS
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 is reachable iff the labeled statement is reachable.
An expression statement can complete normally iff it is reachable.
Anif
-then
statement can complete normally iff it is reachable.
Thethen
-statement is reachable iff theif
-then
statement is reachable.
Anif
-then
-else
statement can complete normally iff thethen
-statement can complete normally or theelse
-statement can complete normally.
Thethen
-statement is reachable iff theif
-then
-else
statement is reachable.
Theelse
-statement is reachable iff theif
-then
-else
statement is reachable.
This handling of anif
statement, whether or not it has anelse
part, is rather unusual. The rationale is given at the end of this section.
Anassert
statement can complete normally iff it is reachable.
Aswitch
statement can complete normally iff at least one of the following is true:
A switch block is reachable iff itsswitch
statement is reachable.
A statement in a switch block is reachable iff itsswitch
statement is reachable and at least one of the following is true:
Awhile
statement can complete normally iff at least one of the following is true:
Thewhile
statement is reachable and the condition expression is not a constant expression (§15.28) with valuetrue
.
There is a reachablebreak
statement that exits thewhile
statement.
The contained statement is reachable iff thewhile
statement is reachable and the condition expression is not a constant expression whose value isfalse
.
Ado
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 valuetrue
.
Thedo
statement contains a reachablecontinue
statement with no label, and thedo
statement is the innermostwhile
,do
, orfor
statement that contains thatcontinue
statement, and thecontinue
statement continues thatdo
statement, and the condition expression is not a constant expression with valuetrue
.
Thedo
statement contains a reachablecontinue
statement with a labelL
, and thedo
statement has labelL
, and thecontinue
statement continues thatdo
statement, and the condition expression is not a constant expression with valuetrue
.
There is a reachablebreak
statement that exits thedo
statement.
The contained statement is reachable iff thedo
statement is reachable.
A basicfor
statement can complete normally iff at least one of the following is true:
Thefor
statement is reachable, there is a condition expression, and the condition expression is not a constant expression (§15.28) with valuetrue
.
There is a reachablebreak
statement that exits thefor
statement.
The contained statement is reachable iff thefor
statement is reachable and the condition expression is not a constant expression whose value isfalse
.
An enhancedfor
statement can complete normally iff it is reachable.
Abreak
,continue
,return
, orthrow
statement cannot complete normally.
Asynchronized
statement can complete normally iff the contained statement can complete normally.
The contained statement is reachable iff thesynchronized
statement is reachable.
Atry
statement can complete normally iff both of the following are true:
Thetry
block is reachable iff thetry
statement is reachable.
Acatch
blockC
is reachable iff both of the following are true:
Either the type ofC
's parameter is an unchecked exception type orException
or a superclass ofException
, or some expression orthrow
statement in thetry
block is reachable and can throw a checked exception whose type is assignable to the type ofC
'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 earliercatch
blockA
in thetry
statement such that the type ofC
's parameter is the same as or a subclass of the type ofA
's parameter.
TheBlock of acatch
block is reachable iff thecatch
block is reachable.
If afinally
block is present, it is reachable iff thetry
statement is reachable.
Onemight expect theif
statement to be handled in the following manner:
Anif
-then
statement can complete normally iff at least one of the following is true:
Theif
-then
statement is reachable and the condition expression is not a constant expression whose value istrue
.
Thethen
-statement can complete normally.
Thethen
-statement is reachable iff theif
-then
statement is reachable and the condition expression is not a constant expression whose value isfalse
.
Anif
-then
-else
statement can complete normally iff thethen
-statement can complete normally or theelse
-statement can complete normally.
Thethen
-statement is reachable iff theif
-then
-else
statement is reachable and the condition expression is not a constant expression whose value isfalse
.
Theelse
-statement is reachable iff theif
-then
-else
statement is reachable and the condition expression is not a constant expression whose value istrue
.
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 statementx=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 statementx=3;
will never be executed and may choose to omit the code for that statement from the generatedclass
file, but the statementx=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 ofDEBUG
fromfalse
totrue
or fromtrue
tofalse
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 noLinkageError
will occur. A change to the value of a flag is, therefore, binary compatible with pre-existing binaries, but not behaviorally compatible.