これは、これらの警告がtry-with-resourcesアプローチでも存在する理由に対する概念的な答えになるでしょう。また、残念ながら、あなたが達成したいと思っている簡単な種類のソリューションではありません。
エラー回復は失敗できません
finally
トランザクションの成功または失敗に関係なく実行されるトランザクション後の制御フローをモデル化します。
失敗した場合、エラーが完全に回復する前(宛先に到達する前)に、エラーからの回復finally
の途中で実行されるロジックをキャプチャしますcatch
。
エラーから回復する途中でエラーが発生するという概念的な問題を想像してください。
トランザクションをコミットしようとしているデータベースサーバーを想像してください。途中で失敗します(サーバーが途中でメモリを使い果たしたなど)。サーバーは、何も起こらなかったように、トランザクションをポイントにロールバックしたいと考えています。しかし、ロールバックのプロセスでさらに別のエラーが発生することを想像してください。これで、データベースに対する半分コミットされたトランザクションができあがります。トランザクションの不可分性と不可分な性質が壊れ、データベースの整合性が損なわれます。
この概念的な問題は、Cが手動のエラーコード伝播を使用している場合でも、C ++で例外とデストラクタを使用している場合でも、Javaを例外およびで使用している場合でもエラーを処理する言語に存在しますfinally
。
finally
デストラクタが例外に遭遇する過程でC ++で失敗するのと同じ方法でそれを提供する言語で失敗することはできません。
この概念的で難しい問題を回避する唯一の方法は、トランザクションをロールバックし、途中でリソースを解放するプロセスで、再帰的な例外/エラーが発生しないようにすることです。
したがって、ここでの唯一の安全な設計は、writer.close()
おそらく失敗しない設計です。通常、設計では、リカバリの途中でそのようなことが失敗して不可能になるシナリオを回避する方法があります。
残念ながら、これが唯一の方法です。エラーリカバリが失敗することはありません。これを確実にする最も簡単な方法は、これらの種類の「リソース解放」および「逆副作用」機能が失敗しないようにすることです。簡単ではありません。適切なエラー回復は難しく、残念ながらテストも困難です。しかし、それを達成する方法は、「破棄」、「閉じる」、「シャットダウン」、「ロールバック」などの関数がプロセスで外部エラーに遭遇しないようにすることです。既存のエラーから回復する途中で呼び出されます。
例:ロギング
finally
ブロック内のデータをログに記録するとします。これは、ロギングが失敗しない限り、大きな問題になることがよくあります。ファイルにさらにデータを追加したい場合があるため、ロギングはほぼ確実に失敗する可能性があり、失敗する多くの理由を簡単に見つけることができます。
したがって、ここでの解決策は、finally
ブロックで使用されるロギング関数が呼び出し元にスローできないようにすることです(失敗する可能性はありますが、スローされません)。どうすればいいですか?入れ子になったtry / catchブロックが存在する場合、言語で最終的にコンテキスト内でのスローが許可されている場合、例外を飲み込んでエラーコードに変えることで呼び出し元へのスローを回避する1つの方法になります。個別に失敗し、既存のエラー回復スタックの外側で失敗する可能性があるプロセスまたはスレッド。エラーが発生する可能性なしにそのプロセスと通信できる限り、同じスレッド内から再帰的にスローする場合にのみ安全性の問題がこのシナリオに存在するため、例外セーフでもあります。
この場合、ログに失敗して何もしないことが世界の終わりではないため、スローされない限り、ログの失敗を回避できます(リソースのリークや副作用のロールバックに失敗しないなど)。
とにかく、ソフトウェアを例外セーフにすることは本当に信じられないほど難しいと想像し始めることができると確信しています。最もミッションクリティカルなソフトウェアを除き、すべてを最大限に追求する必要はないかもしれません。しかし、非常に汎用的なライブラリ作成者でさえも、ライブラリを使用してアプリケーションの例外安全性全体を破壊することが多いため、本当に例外安全性を達成する方法に注意する価値があります。
SomeFileWriter
SomeFileWriter
insideをスローできる場合close
、既存の例外からの回復を伴うコンテキストで決して閉じようとしない限り、一般的に例外処理と互換性がないと思います。そのコードがあなたのコントロールの外にある場合、私たちはSOLかもしれませんが、この露骨な例外安全性の問題について著者に通知する価値があります。それがあなたのコントロール内にある場合、私の主な推奨事項は、それを閉じることはおそらく必要な手段によって失敗しないことを確認することです。
オペレーティングシステムが実際にファイルを閉じることができない場合を想像してください。これで、シャットダウン時にファイルを閉じようとするプログラムはシャットダウンに失敗します。今何をすべきか、アプリケーションを開いたままにし、リンボで(おそらくいいえ)ファイルリソースをリークし、問題を無視します(それほど重大でない場合は大丈夫かもしれません)。最も安全な設計:ファイルを閉じるのに失敗しないようにします。