この質問にはすでに答えがあります。
try / catch / finallyブロックに戻ることを含む頭痛の種に気づいています - たとえtryまたはcatchブロックの中の戻り値が実行されるべきものであっても、finallyの中の戻り値が常にメソッドの戻り値である場合。
しかし、同じことがSystem.exit()にも当てはまりますか?たとえば、tryブロックがあるとします。
try {
//Code
System.exit(0)
}
catch (Exception ex) {
//Log the exception
}
finally {
System.exit(1)
}
例外がない場合は、どのSystem.exit()が呼び出されますか?出口がreturnステートメントの場合は、行System.exit(1)が常に(?)呼び出されます。しかし、exitがreturnと違った振る舞いをするかどうかはわかりません。
そのコードは極端な場合には、不可能ではないにしても再現するのが非常に難しいので、私は単体テストを書くことができません。私は数分の空き時間があったら今日、後で実験を試みるつもりですが、とにかく興味があります、そしておそらくSOの誰かが答えを知っていて、私が実行できない場合に備えてそれを提供できます。実験。
いいえSystem.exit(0)
戻りません、そして、finallyブロックは実行されません。
System.exit(int)
投げることができるSecurityException
。それが起こるなら、finallyブロック意志実行されます。同じプリンシパルが同じコードベースから同じメソッドを呼び出しているので、SecurityException
2番目の呼び出しからスローされる可能性があります。
これが2番目のケースの例です。
import java.security.Permission;
public class Main
{
public static void main(String... argv)
throws Exception
{
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(Permission perm)
{
/* Allow everything else. */
}
@Override
public void checkExit(int status)
{
/* Don't allow exit with any status code. */
throw new SecurityException();
}
});
System.err.println("I'm dying!");
try {
System.exit(0);
} finally {
System.err.println("I'm not dead yet!");
System.exit(1);
}
}
}
StackOverflowException
防ぐためにSystem.exit
スタックフレームの呼び出しでSystem.exit
スタック制限の直前です。このような境界条件はハッカーによって設計されることがあるので、これに依存するセキュリティの不変条件がある場合は、Thread.UncaughtExceptionHandler
それは徹底的な防御として存在します。 - Mike Samuelfinally
実行中のブロック(Ant
アプリケーション起動スクリプトとしてAntを使用しているjava
タスク)または実行されていない(アプリケーションが直接を使用して呼び出された場合)java
コンソールから、なしでAnt
)この回答に基づいて、アプリケーションがAntの内部から呼び出されたときに、このように表示されると思います。java
タスクaSecurityException
スローされます。 - Marcus Junius BrutusStackOverflowException
存在しない(定義しない限り)。それはStackOverflowError
。重要なちょっとした違い。 - Peter Verhas
簡単なテストcatch
それも明らかにsystem.exit(0)
セキュリティ例外をスローしません、それは最後に実行されたステートメントになります(catch
そしてfinally
まったく実行されません)。
もしsystem.exit(0)
セキュリティ例外をスローします。catch
そしてfinally
文が実行されます。両方ともcatch
そしてfinally
含むsystem.exit()
これらのステートメントの前にあるステートメントのみsystem.exit()
文が実行されます。
上記の両方の場合において、try
codeが別のメソッドによって呼び出されたメソッドに属している場合、呼び出されたメソッドは戻りません。
もっと詳しくここに(個人ブログ)
他の回答では、catch
そしてfinally
ブロックは実行されませんSystem.exit
をスローせずにJVMを終了します。SecurityException
しかし、それらはリソースに対する "try-with-resources"ブロックで何が起こるかを示していません:彼らは閉じられていますか?
変換の効果は、リソース指定をtryステートメントの「内側」に置くことです。これにより、拡張されたtry-with-resourcesステートメントのcatch節は、自動初期化または任意のリソースのクローズによる例外をキャッチすることができます。
さらに、finallyキーワードの意図に沿って、finallyブロックが実行されるまでにすべてのリソースが閉じられています(または閉じられようとしています)。
つまり、リソースはclose
aの前にdcatch
またはfinally
ブロックラン彼らがいる場合はどうなりますclose
どういうわけかdcatch
そしてfinally
走らない?
これは、 "try-with-resources"ステートメント内のリソースが閉じられていないことを示すためのコードです。
私はの単純なサブクラスを使用しますBufferedReader
それは呼び出す前にステートメントを出力しますsuper.close
。
class TestBufferedReader extends BufferedReader {
public TestBufferedReader(Reader r) {
super(r);
}
@Override
public void close() throws IOException {
System.out.println("close!");
super.close();
}
}
それから私は電話のテストケースを設定しますSystem.exit
try-with-resourcesステートメントで。
public static void main(String[] args)
{
try (BufferedReader reader = new TestBufferedReader(new InputStreamReader(System.in)))
{
System.out.println("In try");
System.exit(0);
}
catch (Exception e)
{
System.out.println("Exception of type " + e.getClass().getName() + " caught: " + e.getMessage());
}
finally
{
System.out.println("finally!");
}
}
出力:
試してみる
したがって、するだけでなくcatch
そしてfinally
ブロックが実行されない場合、 "try-with-resources"ステートメントは実行されません。close
そのリソースSystem.exit
成功しました。
tryブロックがthrowableをスローしたとしても、最終的にblockは実行されます....
最後にblockが実行されないのは、System.exit()メソッドを呼び出すときだけです。
try{
System.out.println("I am in try block");
System.exit(1);
} catch(Exception ex){
ex.printStackTrace();
} finally {
System.out.println("I am in finally block!!!");
}
finallyブロックは実行されません。プログラムは終了します System.exit()ステートメントの後。
この行動に問題があると考えていて、自分の行動を細かく制御する必要がある場合System.exit
呼び出し、そしてあなたができる唯一のことはあなた自身のロジックでSystem.exit機能をラップすることです。そうすれば、最後にブロックを実行し、出口フローの一部としてリソースを閉じることができます。
私がやろうと思っているのはSystem.exit
電話& A私自身の静的メソッドの機能私の実装ではexit
私はのカスタムサブクラスを投げるだろうThrowable
またはError
そして、カスタムUncaught例外ハンドラをで実装します。Thread.setDefaultUncaughtExceptionHandler
その例外を処理します。したがって、私のコードは次のようになります。
//in initialization logic:
Thread.setDefaultUncaughtExceptionHandler((thread, exception) -> {
if(exception instanceof SystemExitEvent){
System.exit(((SystemExitEvent)exception).exitCode);
}
})
// in "main flow" or "close button" or whatever
public void mainFlow(){
try {
businessLogic();
Utilities.exit(0);
}
finally {
cleanUpFileSystemOrDatabaseConnectionOrWhatever();
}
}
//...
class Utilities {
// I'm not a fan of documentaiton,
// but this method could use it.
public void exit(int exitCode){
throw new SystemExitEvent(exitCode);
}
}
class SystemExitEvent extends Throwable {
private final int exitCode;
public SystemExitEvent(int exitCode){
super("system is shutting down")
this.exitCode = exitCode;
}
}
この戦略には、このロジックをテスト可能にするという追加の「メリット」があります。「メインフロー」を含むメソッドが実際にシステムに終了を要求することをテストするには、スロー可能なオブジェクトをキャッチするだけです。たとえば、ビジネスロジックラッパーのテストは次のようになります。
//kotlin, a really nice language particularly for testing on the JVM!
@Test fun `when calling business logic should business the business`(){
//setup
val underTest = makeComponentUnderTest(configureToReturnExitCode = 42);
//act
val thrown: SystemExitEvent = try {
underTest.mainFlow();
fail("System Exit event not thrown!")
}
catch(event: SystemExitEvent){
event;
}
//assert
assertThat(thrown.exitCode).isEqualTo(42)
この戦略の主な欠点は、それが例外フローから機能を引き出す方法であり、それがしばしば意図しない結果を招くことです。この場合、最も明白なのは、あなたが書いたどこにでもあるということです。try { ... } catch(Throwable ex){ /*doesnt rethrow*/ }
更新する必要があります。カスタム実行コンテキストを持つライブラリの場合、この例外を理解するためにそれらを改良する必要があります。
結局、これは私にとって良い戦略のように思えます。ここで他の誰かがそう思いますか?
以下の例では、System.exit(0)
例外行の前にあると、プログラムは正常に終了するため、FINALLYは実行されません。
あればSystem.exix(0)
tryブロックの最後の行です。ここでは2つのシナリオがあります。
。
package com.exception;
public class UserDefind extends Exception {
private static int accno[] = {1001,1002,1003,1004,1005};
private static String name[] = {"raju","ramu","gopi","baby","bunny"};
private static double bal[] = {9000.00,5675.27,3000.00,1999.00,1600.00};
UserDefind(){}
UserDefind(String str){
super(str);
}
public static void main(String[] args) {
try {
//System.exit(0); -------------LINE 1---------------------------------
System.out.println("accno"+"\t"+"name"+"\t"+"balance");
for (int i = 0; i < 5; i++) {
System.out.println(accno[i]+"\t"+name[i]+"\t"+bal[i]);
//rise exception if balance < 2000
if (bal[i] < 200) {
UserDefind ue = new UserDefind("Balance amount Less");
throw ue;
}//end if
}//end for
//System.exit(0);-------------LINE 2---------------------------------
}//end try
catch (UserDefind ue)
{
System.out.println(ue);
}
finally{
System.out.println("Finnaly");
System.out.println("Finnaly");
System.out.println("Finnaly");
}
}//end of main
}//end of class
throw new Exception("Error");
直前System.exit(0)
その後、コンパイルして、実行可能プログラムから返されるステータスコードを確認します。 - Ki Jéy