web-dev-qa-db-ja.com

Java:キャッチの意味(最終的なSomeException e)?

次のJava式でfinalは何をしますか?

catch (final SomeExceptionType e)
32
PlagueHammer

それは基本的に意味します:

例外の処理中に「e」に別の例外を割り当てないことを約束して、「SomeExceptionType」を変数「e」にキャッチします。

ほとんどの場合、これはやり過ぎです。一時変数名に例外をキャッチしているように(eは例外処理ブロックに対してのみ有効です)、別の名前を割り当てることを自分自身に信頼しないように厳密に自分自身を監視する必要はありません(作成された可能性があります)同じ変数名の例外。

とは言うものの、おそらくこのブロックは、志の異なる個人のチームによって厳重に維持されており、eが最初にキャプチャされた例外であることを非常に確信したかっただけです。

----解説に応じて編集----

私はこれをする本当に素晴らしい理由を考えることができません。 「e」は(静的またはその他の)メンバーではないため、「e」という名前はコンパイル後のクラスファイルでは使用されません。これを示す別の方法は、JVMバイトコードの例外処理ブロックに入ると、オブジェクトはJVM処理フレームによってアクセス可能なメンバー名のいずれにも割り当てられず、スレッドの内部処理スタックにプッシュされるということです。現在のフレーム。

2つのスレッドが同じオブジェクトにアクセスできたとしても、各スレッドには独自のフレームがあるため、コンパイラは一方のフレームの内部スタックから「e」名を削除し、もう一方のスレッドで変更することはできませんでした。

そのことを念頭に置いて、「e」ファイナルを宣言する唯一の利点は、将来のコーダーがブロックに入った後に誤って「e」を設定しないようにすることです。おそらく、マルチスレッド環境でコードをより堅牢にすることを意図していましたが、一時変数(ブロック内でのみ有効な名前を持つ変数)にはコンパイル後に名前がなく、フレームのスタックにプッシュされます。

それが理由です

public int safe() {
  int x = 5;
  x = x + 5;
  return x;
}

これは(疑似バイトコードで)行われるため、一般にスレッドセーフと見なされます

(In the thread's current frame)
Push 5
Push 5
add integers
return

これはスレッドセーフではありませんが

int x = 5;

public void unsafe() {
  x = 5;
  x = x + 5;
  return x;
}

これを行うので

(in the thread's current frame)
Push "this"
Push 5
set member x
Push "this"
get member x
Push 5
add integer
set member x
get member x
return

後者のバイトコードは、2つのスレッドをインターリーブすると、メンバーxを中間体として使用してスレッド間通信が作成されることを示していますが、コードの最初のブロックは、中間体がないため、スレッド間通信を行うことができません。

32
Edwin Buck

現在、それは常に「確実に割り当てられる」ことを除いて、他のローカル変数とほとんど同じfinalを意味します。

最近のJDK7ビルドでは、 Project Coin言語の変更 により、暗黙的な静的型付けが行われていることを示すことができます。単一のcatchは、共通のベースタイプによって多数の異なるチェック済み例外をキャッチし、(静的に言えば)try内でスローされる可能性のある例外のみをキャッチまたは宣言することで、囲んでいるコンテキストで再スローできます。 (より良い説明については、リンクを参照してください。)

11

finalは何をするのですか?」という質問。この質問に対する他の回答、および herehere 、および here で対処されています。しかし、try-catchブロックのコンテキストでは、 Java言語仕様(JLS)§4.12.4は (私自身を強調)を述べています:

  • try-with-resourcesステートメント(§14.20.3)のリソースとmultiの例外パラメーター-catch句(§14.20)は暗黙的に最終宣言されたです。
  • uni-catch節(§14.20)の例外パラメーターは、明示的にfinalと宣言されるのではなく、事実上finalになる場合があります。このようなパラメータは暗黙的にfinalと宣言されることはありませんです。

マルチキャッチ句の場合

finalキーワードをmulti-catch句に追加すると、variableが暗黙的に最終であるという事実が明示されます。一般に、finalキーワードがコードをより読みやすく、保守しやすくするのに役立つ追加情報を伝えるときはいつでも、それを使用してください。

ユニキャッチ句内

一方、ni-catch句の例外パラメータはnever暗黙的にfinalです。したがって、finalキーワードをni-catch句に使用すると、次のようなことが発生しなくなります。

try {
     throw new Exception();
catch (Exception e){
    e = null;
    e.printStackTrace(); //throws a NullPointerException
}

この簡単な例では、問題は明らかです。ただし、2つのケースはあまり明白ではなく、finalの使用が必要な場合があります。

  1. キャッチブロックがより複雑な場合、誤って再割り当てされる可能性があります。 (ただし、catchブロックが複雑な場合は、おそらく間違っています。)
  2. コードのメンテナンス中に発生する問題を防ぐため。例外変数にfinalを追加すると、コンパイル時に再割り当てが確実にキャッチされますランタイムではなく

一般的な経験則として、finalキーワードを使用するのと同じ方法でni-catch句finalキーワードを使用します。メソッドパラメータの場合

JLS§4.12.4 :変数finalを宣言すると、その値が変更されないことを示す有用なドキュメントとして役立ち、プログラミングエラーを回避するのに役立ちます。

5
Austin D

変数のfinalキーワードは、変数を1回しか割り当てることができないことを意味し、ここでの割り当てはコンパイラーによって行われるため、コードの後半で変数を変更できないことを意味します。

これは、この特定の変数が使用されるすべての場所でこの特定の値を持ち、それがどこで変更されるかを追跡する必要がないことを意味するため、重要なプロパティです。これは非常に便利であると認識されているため、Eclipseの「クリーンアップ」アクションでは、可能な限り「最終」を追加できます。このような自動クリーンアップの結果が表示されると思います。 、ほとんどの人間のプログラマーはキャッチブロックを短く保つので、そのような表示は必要ありません。