CHAPTER 14: Blocks and Statements |
|
 Previous |
 Java Language |
 Index |
 Next |
14.19 Unreachable Statements
It is a compile-time error if a statement cannot be executed because it is unreachable. Every Java compiler must carry out the conservative flow analysis specified here to make sure all statements are reachable.
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, 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) n = 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. A Java compiler must operate according to the rules laid out in this section.
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."
The rules are as follows:
- The block that is the body of a constructor, method, or static initializer is reachable.
- An empty block that is not a switch block can complete normally iff it is reachable. A nonempty block that is not a switch block can complete normally iff the last statement in it can complete normally. The first statement in a nonempty block that is not a switch block is reachable iff the block is reachable. Every other statement S in a nonempty block that is not a switch block is reachable iff the statement preceding S can complete normally.
- 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.
- The if
statement, whether or not it has an else
part, is handled in an unusual manner. For this reason, it is discussed separately at the end of this section.
- A switch
statement can complete normally iff at least one of the following is true:
- The last statement in the switch block can complete normally.
- The switch block is empty or contains only switch labels.
- There is at least one switch label after the last switch block statement group.
- There is 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 is reachable iff its switch
statement 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 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 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 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 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 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
.
- 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:
- Some expression or throw
statement in the try
block is reachable and can throw an exception whose type is assignable to the parameter of the catch
clause C. (An expression is considered reachable iff the innermost statement containing it is reachable.)
- 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.
- 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, but these are not the rules that Java actually uses:
- HYPOTHETICAL: 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
.
- HYPOTHETICAL: 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 in Java. However, in order to allow the if statement to be used conveniently for "conditional compilation" purposes, the actual rules are as follows:
- ACTUAL: An if
-then
statement can complete normally iff it is reachable. The then
-statement is reachable iff the if
-then
statement is reachable.
- ACTUAL: 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.
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 a significant impact on, and relationship to, binary compatibility (Chapter 13). 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. A change to the value of a flag is, therefore, not binary compatible with preexisting binaries (S13.4.8). (There are other reasons for such incompatibility as well, such as the use of constants in case
labels in switch
statements; see S13.4.8.)
 | © 1996 Sun Microsystems, Inc. All rights reserved. |