代码之家  ›  专栏  ›  技术社区  ›  Thomas Owens

Java的.ExtEx()如何与Test/Ccatch/Bug块一起工作?[复制品]

  •  60
  • Thomas Owens  · 技术社区  · 15 年前

    这个问题已经有了答案:

    我知道在try/catch/finally块中返回会带来一些头痛——在这种情况下,finally中的返回始终是方法的返回,即使try或catch块中的返回应该是执行的返回。

    但是,这同样适用于system.exit()吗?例如,如果我有一个try块:

    try {
        //Code
        System.exit(0)
    }
    catch (Exception ex) {
        //Log the exception
    }
    finally {
        System.exit(1)
    }
    

    如果没有异常,将调用哪个system.exit()?如果exit是一个返回语句,那么行system.exit(1)将始终(?)被召唤。但是,我不确定exit的行为是否与return不同。

    在极端情况下,代码很难(如果不是不可能的话)重现,所以我不能编写单元测试。今天晚些时候,如果我有几分钟的空闲时间,我会尝试运行一个实验,但我还是很好奇,也许有人知道答案,可以在之前提供答案,或者万一我不能运行一个实验。

    6 回复  |  直到 8 年前
        1
  •  73
  •   erickson    15 年前

    不。 System.exit(0) 不返回,并且不执行finally块。

    System.exit(int) 可以扔 SecurityException . 如果发生这种情况,最后一个街区 执行。由于相同的主体从相同的代码基调用相同的方法,因此 安全例外 可能会从第二个调用中抛出。


    下面是第二个案例的一个例子:

    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);
        }
      }
    
    }
    
        2
  •  7
  •   Jérôme Verstrynge Mark    12 年前

    简单测试包括 catch 太暴露如果 system.exit(0) 不引发安全异常,它将是最后执行的语句( 抓住 finally 完全不执行)。

    如果 退出系统(0) 是否引发安全异常, 抓住 最后 语句被执行。如果两者 抓住 最后 包含 system.exit() 声明,仅在此之前的声明 系统。 语句被执行。

    在上述两种情况下,如果 try 代码属于另一个方法调用的方法,被调用的方法不返回。

    更多细节 here (个人博客)。

        3
  •  4
  •   rgettman    8 年前

    其他答案包括 catch finally 块不运行如果 System.exit 退出JVM而不引发 SecurityException 但它们不显示资源的“使用资源尝试”块中发生的情况:它们是否已关闭?

    根据 JLS, Section 14.20.3.2 :

    翻译的效果是将资源规范“放在”try语句中。这允许扩展try with resources语句的catch子句捕获由于任何资源的自动初始化或关闭而导致的异常。

    此外,根据finally关键字的意图,在执行finally块时,将关闭(或尝试关闭)所有资源。

    也就是说,资源 close 前一天 抓住 最后 块运行。如果是呢 关闭 D不管怎样,即使 抓住 最后 不要跑?

    下面是一些代码来证明“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();
        }
    }
    

    然后我设置了调用的测试用例 退出系统 在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!");
        }
    }
    

    输出:

    在尝试中

    因此,不仅如此 抓住 最后 块未运行,“Try with Resources”语句将无法 关闭 它的资源如果 退出系统 成功了。

        4
  •  3
  •   mezzodrinker    8 年前

    无论发生什么,最终块都将被执行…即使try块抛出任何可丢弃的(异常或错误)……

    唯一不执行的case finally块是调用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()语句之后。

        5
  •  2
  •   Groostav    8 年前

    如果你认为这种行为有问题,你需要对你的 System.exit 调用,那么您唯一能做的就是用您自己的逻辑包装system.exit功能。如果这样做,我们就可以最终执行块,并将资源作为退出流的一部分关闭。

    我正在考虑做的是包装 退出系统 在我自己的静态方法中调用&功能。在我的实施中 exit 我将抛出的自定义子类 Throwable Error ,并使用 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*/ } 必须更新。对于具有自定义执行上下文的库,需要对它们进行改装以了解此异常。

    总的来说,这对我来说似乎是一个很好的策略。这里还有人这么认为吗?

        6
  •  0
  •   Rohit Gupta fevangelou    9 年前
    1. 在下面的示例中,如果 System.exit(0) 在异常行之前,程序将正常终止,因此最终不会执行。

    2. 如果 System.exix(0) 是try块的最后一行,这里有两个场景

      • 当出现异常时,最后执行块
      • 如果不存在异常,则不执行finally块

    .

    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