【问题标题】:what is the exact order of execution for try, catch and finally?try、catch 和 finally 的确切执行顺序是什么?
【发布时间】:2013-07-26 07:12:57
【问题描述】:

在这个java代码中,

import java.io.IOException;

public class Copy
{
   public static void main(String[] args)
   {
      if (args.length != 2)
      {
         System.err.println("usage: java Copy srcFile dstFile");
         return;
      }

      int fileHandleSrc = 0;
      int fileHandleDst = 1;
      try
      {
         fileHandleSrc = open(args[0]);
         fileHandleDst = create(args[1]);
         copy(fileHandleSrc, fileHandleDst);
      }
      catch (IOException ioe)
      {
         System.err.println("I/O error: " + ioe.getMessage());
         return;
      }
      finally
      {
         close(fileHandleSrc);
         close(fileHandleDst);
      }
   }

   static int open(String filename)
   {
      return 1; // Assume that filename is mapped to integer.
   }

   static int create(String filename)
   {
      return 2; // Assume that filename is mapped to integer.
   }

   static void close(int fileHandle)
   {
      System.out.println("closing file: " + fileHandle);
   }

   static void copy(int fileHandleSrc, int fileHandleDst) throws IOException
   {
      System.out.println("copying file " + fileHandleSrc + " to file " +
                         fileHandleDst);
      if (Math.random() < 0.5)
         throw new IOException("unable to copy file");

      System.out.println("After exception");
   }
}

我期望的输出是

copying file 1 to file 2
I/O error: unable to copy file
closing file: 1
closing file: 2

但有时我会得到这个预期的输出,而在其他时候我会得到以下输出:

copying file 1 to file 2
closing file: 1
closing file: 2
I/O error: unable to copy file  

有时甚至是这样的输出:

I/O error: unable to copy file
copying file 1 to file 2
closing file: 1
closing file: 2

在每次执行期间,我是否得到第一个、第二个或第三个输出似乎都是随机发生的。我发现THIS POST 显然在谈论同样的问题,但我仍然不明白为什么我有时会得到输出 1、2 或 3。如果我正确理解这段代码,那么输出 1 应该是我每次得到的(例外发生)。如何确保始终获得输出 1,或者能够判断何时获得输出 1 或何时获得 得到输出 2 还是 3?

【问题讨论】:

标签: java exception


【解决方案1】:

问题是您正在将一些输出写入System.out 和一些System.err。这些是独立的流,具有独立的缓冲。据我所知,它们被刷新的时间没有具体说明。

简而言之,当写入不同的流时,您不能使用输出显示的顺序来确定对println() 的调用发生的顺序。请注意,System.out 的输出始终按预期顺序显示。

就执行顺序而言,try 的主体首先执行。如果它抛出异常,则执行相应的catch 子句的主体。 finally 块总是最后执行。

【讨论】:

  • 但理论上,顺序应该是输出 1 中显示的顺序,不是吗?
  • @user13267 - 是的。执行顺序是指定的,它对应于您期望的输出顺序。让所有内容都进入一个流(例如,System.out),您应该每次都能看到预期的订单。或者,在每次写入后立即在每个输出流上调用flush()。这也应该修复输出出现在控制台上的顺序。
  • 我在每次调用System.out.flush()System.err.flush() 时都尝试过,但输出顺序仍然保持不变。
  • 但是,总是将所有内容写入System.out 似乎每次都以正确的顺序显示它
  • @user13267 - 当您调用flush() 时,“输出顺序保持不变”是什么意思?您的意思是您仍然偶尔会得到意外的输出顺序吗?或者你的意思是输出总是相同的顺序(从不改变)?
【解决方案2】:

使用 try catch 块处理异常的事情是,如果有任何异常进入 catch 块,控件将进入 try。但是控件每次执行都会进入final block。

【讨论】:

    【解决方案3】:

    您正在将错误消息写入标准输出和标准错误。它们具有不同的缓冲区,因此无法保证您看到的输出在两个输出流之间的顺序与您创建它的顺序相同。

    由于我在您的代码中看不到任何错误(尽管您的 catch 段中多余的 return; 有点卡在我的抓取中),所以我建议您将所有消息写入 stderr,看看是否消息顺序更符合您的预期。

    【讨论】:

      【解决方案4】:

      您的示例中有一个故障,我将删除它。您正在写入 System.out 和 System.err 并期望您的控制台正确同步两个流。为了消除副作用,我在这里只使用一个流。

      【讨论】:

        【解决方案5】:

        首先执行Try块,如果成功,最后执行,如果try块失败,则catch将执行,finally执行。发生的事情 finally 块都会执行。

        但是

        如果你调用System.exit(0) finally 块不执行

        【讨论】:

        • 最终块会执行什么我不同意如果 System.exit() 被调用怎么办?
        • @Sunny 是的,你是对的,但我只是在谈论这个案例。如果您在尝试中调用 System.exit(0)。或者做一些使 JVM 退出或挂起的事情(比如死锁)。否则 - 不。
        猜你喜欢
        • 2013-12-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-18
        • 1970-01-01
        • 2021-05-30
        • 1970-01-01
        相关资源
        最近更新 更多