このJavaケースの詳細(おそらくC#ケースと非常によく似ています)は、Javaコンパイラーがメソッドが戻ることができるかどうかをどのように決定するかに関係しています。
具体的には、JLS 8.4.7に従って、戻り値の型を持つメソッドは正常に完了できず、常に突然(ここではreturnステートメントまたは例外を介して示す)完了する必要があるという規則があります。
メソッドが戻り値の型を持つように宣言されている場合、メソッドの本体が正常に完了すると、コンパイル時エラーが発生します。つまり、戻り値の型を持つメソッドは、値を返すreturnステートメントを使用することによってのみ戻る必要があります。「体の端を降ろす」ことはできません。
コンパイラーは、JLS 14.21到達不能ステートメントで定義された規則に基づいて、正常終了が可能かどうかを調べます。これは、正常終了の規則も定義しているためです。
特に、到達不能ステートメントのルールは、true
定数式が定義されているループに対してのみ特別なケースを作ります:
whileステートメントは、以下の少なくとも1つが当てはまる場合に通常どおり完了できます。
したがって、while
ステートメントが正常に完了できる場合、コードは到達可能と見なされるため、その下のreturnステートメントが必要です。while
到達可能なbreakステートメントまたは定数true
式のないループは、正常に完了できると見なされます。
これらの規則はwhile
、定数の真の式を含み、a break
を含まないステートメントが正常に完了するとは決して見なされないため、そのステートメントの下にあるコードは到達可能であると見なされないことを意味します。メソッドの終わりはループの下にあり、ループの下にあるすべてのものには到達できないため、メソッドの終わりにもなり、メソッドは正常に完了できない可能性があります(コンパイラーが探しているものです)。
if
一方、ステートメントには、ループに使用できる定数式に関する特別な免除はありません。
比較:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
と:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
区別の理由は非常に興味深いものであり、(JLSからの)コンパイラエラーを引き起こさない条件付きコンパイルフラグを許可したいという欲求によるものです。
ifステートメントが次のように処理されることを期待できます。
if-thenステートメントは、以下の少なくとも1つが当てはまる場合に通常どおり完了できます。
thenステートメントは、if-thenステートメントが到達可能で、条件式が値がfalseの定数式でない場合に到達可能です。
if-then-elseステートメントは、thenステートメントが正常に完了できるか、elseステートメントが正常に完了できる場合に限り、正常に完了できます。
このアプローチは、他の制御構造の扱いと一致します。ただし、ifステートメントを「条件付きコンパイル」の目的で便利に使用できるようにするために、実際のルールは異なります。
例として、次のステートメントはコンパイル時エラーになります。
while (false) { x=3; }
ステートメントにx=3;
到達できないため。しかし、表面的には同様のケース:
if (false) { x=3; }
コンパイル時エラーにはなりません。最適化コンパイラは、ステートメントx=3;
が決して実行されないことを認識し、生成されたクラスファイルからそのステートメントのコードを省略することを選択できますが、ステートメントx=3;
は、ここで指定された技術的な意味で「到達不能」とは見なされません。
この異なる処理の理論的根拠は、プログラマが次のような「フラグ変数」を定義できるようにすることです。
static final boolean DEBUG = false;
次に、次のようなコードを記述します。
if (DEBUG) { x=3; }
これは、DEBUGの値をfalseからtrueまたはtrueからfalseに変更し、プログラムテキストを変更せずにコードを正しくコンパイルできるようにする必要があるという考え方です。
条件付きbreakステートメントでコンパイラエラーが発生するのはなぜですか?
ループの到達可能性ルールで引用されているように、whileループは、到達可能なbreakステートメントが含まれていれば、正常に完了することもできます。if
ステートメントのthen句の到達可能性に関するルールは、の条件をif
まったく考慮しないため、このような条件付きif
ステートメントのthen句は常に到達可能と見なされます。
break
が到達可能である場合、ループ後のコードも到達可能と見なされます。ループ後に突然終了するコードには到達できないため、メソッドは正常に完了したと見なされ、コンパイラーはエラーとしてフラグを立てます。