インタビューで、tryブロックとcatchブロックの間にfinallyブロックを配置するとどうなるかという質問がありました。その場合、コンパイラはcatchブロックがないと見なし、finallyブロックを直接実行します。次に、tryブロックとcatchブロックの間にコードを配置できないのはなぜですか?
手伝ってくれませんか...
まず最初に、コンパイラはコードを実行するのではなく、コンパイルするだけで、JVM で実行できるようにします。
経験的に言えば、それはあまり意味がありません。なぜなら、try ブロックの外側で catch ブロックの前に配置したいコードがある場合、コードを try ブロックに配置することもできるからです。問題は、考えてみれば、とにかく try ブロックにあったように動作するということです。
これが有効な Java であると仮定しましょう(これはコンパイルされません):
try {
throw new Exception();
}
System.out.println("Sup!");
catch(Exception e) { }
例外がスローされると、JVM が処理する適切な例外ハンドラーにジャンプするために検索しているため、出力されるその行はSup!
スキップされますException
。したがって、ある意味では、コードは try {} ブロック自体にある場合と同じように動作します。そのため、コードがどこにあるかは問題ではなく、Java では、この (現在は役に立たないことが証明されている) 構造は次のように指定されています。違法。
try の後のコードが別の例外自体をスローした場合はどうなるでしょうか。有効なコードであれば、元の try ブロックに入れ子になった try...catch ブロックのように動作します。もちろん、物事が複雑になり始めると、try ブロックと catch ブロックの間に明確な接続がないアプローチはあいまいになる可能性があり、JVM はどの catch/finally がどの try ブロックに属しているかを認識できなくなる可能性があります (特にハンドラーが同じ関数にある必要はなく、同じパッケージにある必要さえありません!)。
まあ、軽率な答えは、言語仕様で禁止されているということです。
しかし、少し戻って別の方法で考えてみましょう。これができるとしたらどうでしょうか。
try {
foo();
}
bar();
catch (Exception e) {
baz();
}
これのセマンティクスは何でしょうか? で例外をキャッチするとfoo()
、 がbaz()
呼び出されますか? どうbar()
ですか?スローされた場合bar()
、その場合に例外をキャッチしますか?
の例外bar()
がキャッチされずfoo()
、例外が実行されないbar()
場合、構文は次と同等です。
try {
foo();
} catch (Exception e) {
baz();
}
bar();
の例外bar()
がキャッチされ、例外の実行がfoo()
妨げられるbar()
場合、構文は次と同等です。
try {
foo();
bar();
} catch (Exception e) {
baz();
}
の例外bar()
がキャッチされず、例外の実行が妨げられfoo()
ないbar()
(bar()
が常に実行される) 場合、構文は次と同等です。
try {
foo();
} catch (Exception e) {
baz();
} finally {
bar();
}
おわかりのように、この between-try-catch 構造の妥当なセマンティクスは、新しい (そしてややこしい) 構造を必要とせずにすでに表現可能です。まだ冗長でないこの構造の意味を考案するのは困難です。
余談ですが、これができない理由として考えられるのは次の 1 つです。
try {
foo();
} finally {
bar();
} catch (Exception e) {
baz();
}
実際の実行順序を反映していない可能性があります - catch ブロックは finally ブロックの前に実行されます。これにより、catch ブロックは、finally ブロックが後で解放する可能性のあるリソースを利用できます (たとえば、RPC オブジェクトなどから追加の診断情報を要求するため)。他の方法でも機能するようにすることはできますか?もちろん。その価値はありますか?おそらくそうではありません。
それは次のような意味になります。
try
{
somCode();
}
someMoreCode();
catch
{
}
これはどういう意味ですか? セマンティックがないため、これは不可能です。したがって、言語設計者によって構文的に正しくないと判断されました。
Java 言語仕様 14.20 "The try ステートメント` で定義されているように、またはのtry
いずれかが必要です。catch
finally
.. if と else .. のように try と catch を行うため、try と catch ブロックの間にコードを追加する必要はありません