finallyブロックの中では、return, break, continue, throw文を決して使用してはならない。プログラムの実行が finallyブロックを持つ tryブロックに入ると、try ブロック(や対応するcatchブロック)の処理が完了するかしないかに関わらず、finallyブロックは必ず実行される。finally ブロックの処理を途中で終了させる文は、try ブロックの処理も中断させてしまう。そのため、tryブロックやcatchブロックからスローされる例外を抑制してしまう。[JLS 2005]
違反コード
以下の違反コードでは、return文が存在するため、finallyブロックの処理が途中で終了してしまう。
class TryFinally { private static boolean doLogic() { try { throw new IllegalStateException(); } finally { System.out.println("logic done"); return true; } } }
return文によってfinallyブロックの処理が終了しているため、IllegalStateException例外の発生が抑制されている。
適合コード
以下の解決法では、finally ブロックから return 文を取り除いている。
class TryFinally { private static boolean doLogic() { try { throw new IllegalStateException(); } finally { System.out.println("logic done"); } // return 文はここに書くこと。ただし、条件に応じて例外がスローされる // 場合のみ。 } }
例外
ERR04-EX0: finallyブロック内で完結する制御フロー文を書くことは構わない。
たとえば、以下のコードはこのルールの違反には当たらない。break文はwhileループを終了させはするが、finallyブロックは終了させていないからである。
class TryFinally { private static boolean doLogic() { try { throw new IllegalStateException(); } finally { int c; try { while ((c = input.read()) != -1) { if (c > 128) { break; } } } catch (IOException x) { // ハンドラへ処理を移す } System.out.println("logic done"); } // return 文はここに書くこと。ただし、条件に応じて例外がスローされる場合のみ。 } }
リスク評価
finallyブロックの処理を途中で終了すると、tryブロックやcatchブロックの外にスローされるべき例外がスローされなくなってしまう。
ルール | 深刻度 | 可能性 | 修正コスト | 可能性 | レベル |
---|---|---|---|---|---|
ERR04-J | 低 | 中 | 中 | P4 | L3 |
関連ガイドライン
MITRE CWE | CWE-459. Incomplete cleanup |
CWE-584. Return inside finally block |
参考文献
[Bloch 2005] | Puzzle 36. Indecision |
[Chess 2007] | 8.2, Managing Exceptions, The Vanishing Exception |
[JLS 2005] | §14.20.2, Execution of try-catch-finally |
翻訳元
これは以下のページを翻訳したものです。
ERR04-J. Do not exit abruptly from a finally block (revision 82)