35

この関数を考えてみましょう:

public boolean foo(){
   System.exit(1);
   //The lines beyond this will not be read
   int bar = 1;                  //L1
   //But the return statement is required for syntactically correct code
   return false;                 //L2

   //error here for unreachable code
   //int unreachable = 3;        //L3

}

L1とL2が目に見えて到達できないのに、L3が警告を発しない理由を説明してください。

4

8 に答える 8

49

コンパイラに関する限り、System.exit()は別のメソッド呼び出しにすぎないためです。

それがプロセスを終了するという事実は、実装からのみ見つけることができます (これはネイティブ コードであり、違いはありません)。

コードを挿入する必要がSystem.exit()ある場合 (0 以外のコードを返したい場合を除き、通常は避けるのが最善です)、たとえばvoid、を返すメソッド内に挿入する必要があります。main()その方が楽です。

到達可能性については、説明は同じです。Java 言語のキーワードであるため、IDE が使用するコンパイラまたはパーサーは、ステートメントreturnの後のコードを実行することは理論的に不可能であると判断できます。returnこれらのルールはここで定義されています。

于 2012-07-14T20:36:55.750 に答える
15

Java コンパイラは について何も知りませんSystem.exit。それに関する限り、これは単なるメソッドであるため、ステートメントの最後に到達できます。

あなたはそれを言い、 「目に見えて到達できない」と言っていますが、それはあなたが何をするかを知っているからです。言語はそうではありません、ステートメントが何をするかは知っていますが、実際には到達できないことを知っています。L1L2System.exitreturnL3

メソッドvoid単に. コンパイラはその情報を使用して、呼び出し式の最後に到達できないようにし、この種の問題を防ぐことができます。ただし、これは言語設計に関する私の夢です。Javaには類似したものはありません。その概念を表現できない場合に、特定の JRE メソッドが正常に返らないことをコンパイラが「認識する」ことは非常に悪い考えです。言語内で直接。

代わりに、コンパイラは、次のような JLS のセクション 14.21 の規則に拘束されます。

  • switch ブロックではない空でないブロックの最初のステートメントは、ブロックが到達可能である場合に到達可能です。
  • switch ブロックではない空でないブロック内の他のすべてのステートメント S は、S の前のステートメントが正常に完了できる場合に到達可能です。

...

式ステートメントは、到達可能であれば正常に完了できます。

(メソッド呼び出しは式ステートメントです。)

次に、セクション 8.4.7 から:

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

そして14.1では:

特に指定がない限り、ステートメントが評価するすべての式と実行するすべてのサブステートメントが正常に完了する場合、ステートメントは正常に完了します。

System.exit()したがって、コンパイラに関する限り、への呼び出しは正常fooに完了できます。つまり、メソッドの本体が正常に完了し、エラーが発生します。

于 2012-07-14T20:36:49.023 に答える
9

私:「return ステートメントの後に実行できるものはありますか?」
ジャバ:「いいえ」

私: 「System.exit を呼び出した後、何か実行できますか?」
Java: 「これはメソッドです。何をするのかわかりません。予約済みのキーワードではありません。私の知る限り、プログラム フローには影響しません」例外をスローできます (またはその将来のバリアント)))

于 2012-07-14T20:41:58.253 に答える
7

言語の観点から、現在のスコープをエスケープする方法は 2 つしかありません:returnthrow. メソッド呼び出しは、コード行のみで構成されている場合でも、同じように見なされることはありません。

void method() {
  throw new RuntimeException();
}

さらに。理論的には、どのメソッド呼び出しでRuntimeExceptionもスローされる可能性があります。tryこの場合、コンパイラは、ブロック内にないメソッド呼び出しに対して警告を表示するはずです。

...
method(); // WARNING: may throw in theory
anotherMethod(); // WARNING: possible unreachable code, also may throw
anotherMethod2(); // WARNING: possible unreachable code, also may throw
// etc
...

あなたの質問のロジックは同じです。

于 2012-07-14T20:36:45.810 に答える
2

メソッドが void 以外の値を返すように宣言されている場合は、到達していなくても (問題のコードのように) どこかにステートメントが含まれている必要があります。return

コンパイラの観点からは、これSystem.exit()は単なる別のメソッド呼び出しであり、到達するとすぐにプログラムが終了することを示す特別なことは何もありません。この事実を知っているのはプログラマーであるあなただけですが、それはコンパイラーの知識外のものです。

質問の2番目の部分について-returnメソッド内のコードブロック内のステートメントの後には、常に到達できないコードになるため、何もできません。これが、コンパイラが L3 行について不平を言う理由を説明しています。

于 2012-07-14T20:36:59.557 に答える
2

コンパイラは、一部のコードが return キーワードに関してのみ到達可能かどうかをチェックします (一般に、throw と break (ループの場合) も同様です)。コンパイラにとって、exit メソッド呼び出しは単なる別の呼び出しであり、その意味を認識していないため、その後のコードに決して到達しないことを認識していません。

于 2012-07-14T20:37:10.137 に答える
2

これが意味をなさないことはわかっていますが、メソッドを呼び出すときのJavaコンパイラの動作はこれです。
この時点では、コンパイラは Sytem.exist が何をするかを認識していません (その意味で、なぜ rt.jar が、コンパイルで使用する他の jar と異なる必要があるのでしょうか?)。
これは、たとえば次のコードとは対照的です -

 public int test() {
  throw new NullPointerException("aaaa");
}

例外が常にスローされることをコンパイラが判断できる場合、したがってリターンは必要ありません。

于 2012-07-14T20:40:15.120 に答える
0

静的コード分析ツールが、アプリケーションの終了を考慮していない可能性があります。

于 2012-07-14T20:36:59.070 に答える