87

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() が呼び出されますか? exit が return ステートメントの場合、System.exit(1) 行が常に (?) 呼び出されます。ただし、exit の動作が return と異なるかどうかはわかりません。

このコードは、不可能ではないにしても再現が非常に困難な極端なケースにあるため、単体テストを書くことはできません。数分の空き時間があれば、今日の後半に実験を実行しようと思いますが、とにかく興味があります.SOの誰かが答えを知っていて、前に、または実行できない場合に備えて提供できます.実験。

4

6 に答える 6

85

No.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);
    }
  }

}
于 2009-09-11T13:45:31.617 に答える
11

catchtoo を含む簡単なテストsystem.exit(0)では、セキュリティ例外がスローされない場合、それが最後に実行されたステートメントになる (catchそしてfinallyまったく実行されない) ことが明らかになります。

ifsystem.exit(0)はセキュリティ例外をスローし、catchステートメントfinallyが実行されます。と の両方にステートメントが含まれている場合、catchこれらfinallysystem.exit()ステートメントの前にsystem.exit()あるステートメントのみが実行されます。

上記のどちらの場合でも、tryコードが別のメソッドによって呼び出されるメソッドに属している場合、呼び出されたメソッドは戻りません。

詳細はこちら(個人ブログ)。

于 2012-07-28T20:26:33.663 に答える
8

他の回答では、 をスローせずに JVM を終了した場合にcatchおよびfinallyブロックが実行されない方法について説明していますが、リソースへの「try-with-resources」ブロックで何が起こるかは示されていません。System.exitSecurityException

JLS によると、セクション 14.20.3.2 :

変換の効果は、リソース仕様を try ステートメントの「内側」に置くことです。これにより、拡張された try-with-resources ステートメントの catch 句で、リソースの自動初期化またはクローズによる例外をキャッチできます。

さらに、finally キーワードの意図に沿って、finally ブロックが実行されるまでに、すべてのリソースが閉じられている (または閉じようとしている) ことになります。

つまり、またはブロックが実行されるclose前にリソースが削除されます。走らなくても何とかdされたら?catchfinallyclosecatchfinally

「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!");
    }
}

出力:

試しに

したがって、docatchおよびブロックが実行されないだけでなく、"try-with-resources" ステートメントが成功した場合、そのリソースfinallyにチャンスがありません。closeSystem.exit

于 2015-11-20T20:00:23.173 に答える
4

finally ブロックは何があっても実行されます.... try ブロックがスロー可能なもの (例外またはエラー) をスローしたとしても.....

最終的にブロックが実行されない場合のみ... 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!!!");
}

最終ブロックは実行されません。プログラムは System.exit() ステートメントの後で終了します。

于 2014-07-06T08:50:03.060 に答える
3

この動作に問題があり、System.exit呼び出しを細かく制御する必要がある場合は、独自のロジックで System.exit 機能をラップするしかありません。これを行うと、finally ブロックを実行し、終了フローの一部としてリソースを閉じることができます。

私が考えているのは、System.exit呼び出しと機能を自分の静的メソッドにラップすることです。の実装では、 orexitのカスタム サブクラスをスローし、その例外を処理するカスタム Uncaught 例外ハンドラを実装します。したがって、私のコードは次のようになります。ThrowableErrorThread.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;
  }
} 

この戦略には、このロジックをテスト可能にする追加の「利点」があります。「メイン フロー」を含むメソッドが実際にシステムの終了を要求していることをテストするには、throwable をキャッチして、それが書き込みタイプであることをアサートするだけです。たとえば、ビジネス ロジック ラッパーのテストは次のようになります。

//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*/ }更新しなければならないということです。カスタム実行コンテキストを持つライブラリの場合、この例外を理解するためにそれらを改造する必要があります。

全体として、これは私にとって良い戦略のように思えます。ここにそう思う人は他にいますか?

于 2016-09-19T17:46:05.747 に答える
0
  1. 以下の例でSystem.exit(0)は、 が例外行の前にある場合、プログラムは正常に終了するため、FINALLY は実行されません。

  2. これが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
于 2015-08-15T05:17:10.940 に答える