web-dev-qa-db-ja.com

戻り型のあるJavaメソッドは、returnステートメントなしでコンパイルします

質問1:

次のコードがreturnステートメントを持たずにコンパイルするのはなぜですか?

public int a() {
    while(true);
}

注意:しばらくしてからreturnを追加すると、Unreachable Code Errorが返されます。

質問2:

一方、なぜ次のコードがコンパイルされるのですか、

public int a() {
    while(0 == 0);
}

以下はしませんが。

public int a(int b) {
    while(b == b);
}
225
Willi Mentzel

質問1:

次のコードがreturnステートメントなしでコンパイルされるのはなぜですか?

public int a() 
{
    while(true);
}

これは JLS§8.4.7 でカバーされています:

メソッドが戻り型を持つように宣言されている場合(§8.4.5)、メソッドの本体が正常に完了すると(§14.1)コンパイル時エラーが発生します。

つまり、戻り値の型を持つメソッドは、値を返すreturnステートメントを使用することによってのみ戻ります。このメソッドは、「その本体の端から落ちる」ことは許可されていません。メソッド本体のreturnステートメントに関する正確なルールについては、§14.17を参照してください。

メソッドに戻りタイプがあり、まだreturnステートメントが含まれていない可能性があります。次に例を示します。

class DizzyDean {
    int pitch() { throw new RuntimeException("90 mph?!"); }
}

コンパイラーはループが終了しないことを知っているので(もちろん、trueは常にtrueです)、関数が「正常に戻る」ことはできないこと(本体の終わりからドロップオフすること)を知っているため、returnがなくてもかまいません。

質問2:

一方、次のコードがコンパイルされるのはなぜですか、

public int a() 
{
    while(0 == 0);
}

以下はしませんが。

public int a(int b)
{
    while(b == b);
}

0 == 0の場合、コンパイラーはループが終了しないことを知っています(0 == 0は常にtrueになります)。しかし、それはdoes n'tb == bのことを知りません。

何故なの?

コンパイラは 定数式(§15.28) を理解します。引用 §15.2-式の形式(奇妙なことに、この文は§15.28にないため)

一部の式には、コンパイル時に決定できる値があります。これらは定数式(§15.28)です。

b == bの例では、関連する変数があるため、定数式ではなく、コンパイル時に決定されるように指定されていません。 Weは、この場合常にtrueになることがわかります(ただし、QBruteでbdoubleだった場合 pointed outDouble.NaN自体ではない==に簡単にだまされる可能性がありますが、JLSではコンパイル時に定数式が決定されることのみが指定されており、コンパイラが非-定数式。 bayou.io 良い点を挙げた 理由:コンパイル時に変数を含む式を決定しようとする道を歩み始めたら、どこで止めますか? b == bは明白ですが(NaN以外の値の場合)、a + b == b + aはどうですか?または(a + b) * 2 == a * 2 + b * 2?定数で線を引くことは理にかなっています。

したがって、式を「決定」しないため、コンパイラーはループが終了しないことを知らないため、メソッドは正常に戻ることができると考えています。これはreturnを使用する必要があるため許可されていません。したがって、returnの欠如について不満を述べています。

274
T.J. Crowder

メソッドの戻り値の型を、指定された型の値を返す約束としてではなく、notである値を返す約束としてnotと考えると興味深い場合があります指定されたタイプ。したがって、何も返さなければ、約束を破ることはないので、次のいずれかが有効です。

  1. 永遠にループ:

    X foo() {
        for (;;);
    }
    
  2. 永遠に再帰:

    X foo() {
        return foo();
    }
    
  3. 例外を投げる:

    X foo() {
        throw new Error();
    }
    

(再帰について考えるのは楽しいことです:コンパイラは、メソッドがX型(それが何であれ)の値を返すと信じていますが、実際にはコードが存在しないため、そうではありませんXを作成または調達する方法を考えてください。)

33
Boann

バイトコードを見ると、返されているものが定義と一致しない場合、コンパイルエラーが発生します。

例:

for(;;)はバイトコードを表示します:

L0
    LINENUMBER 6 L0
    FRAME SAME
    GOTO L0

戻り値のバイトコードがないことに注意してください

これはリターンをヒットすることはないため、間違ったタイプを返すことはありません。

比較のために、次のようなメソッド:

public String getBar() { 
    return bar; 
}

次のバイトコードを返します。

public Java.lang.String getBar();
    Code:
      0:   aload_0
      1:   getfield        #2; //Field bar:Ljava/lang/String;
      4:   areturn

「参照を返す」という意味の「戻り」に注意してください

ここで次のことを行うと:

public String getBar() { 
    return 1; 
}

次のバイトコードを返します。

public String getBar();
  Code:
   0:   iconst_1
   1:   ireturn

これで、定義内の型がireturnの戻り型と一致しないことがわかります。これは、intを返すことを意味します。

つまり、メソッドに戻りパスがある場合、そのパスは戻り型と一致する必要があります。ただし、バイトコードには、リターンパスがまったく生成されないため、ルールに違反しないインスタンスがあります。

8
Philip Devine