【问题标题】:Is this pattern for handling IO exceptions in Java correct?这种在 Java 中处理 IO 异常的模式是否正确?
【发布时间】:2013-11-29 11:43:57
【问题描述】:

在下面的代码sn-p中,如果ex1被抛出,会被第二个catch块捕获,还是会被扔回给方法的调用者?

如果将其抛回给调用者,然后在 finally 块(ex2)中发生第二个异常,是否意味着将有 2 个异常被抛回给调用者(ex1 和 ex2)?

try {
  // write to file
} catch (IOException ex1) {
  throw ex1;
} finally {
  try {
    aBufferedWriter.close();
  } catch (IOException ex2) {
    throw ex2;
  }
}

【问题讨论】:

  • 如果你只是重新抛出异常,那么捕获它是没有意义的。
  • 为什么当你把它扔进你的渔获物时,你甚至会抓住它?

标签: java io


【解决方案1】:

这两个异常都会被抛出给调用者......尽管在任何特定情况下都会出现一个异常。如果外部 try 块的主体抛出,然后 close 也抛出,调用者只会看到第二个异常。

但是,仅仅为了重新抛出一个 catch 块是没有意义的。您的代码会更清晰:

try {
  // write to file
} finally {
  aBufferedWriter.close();
}

在 Java 7 中,try-with-resources statement 可以自动执行此操作:

try (BufferedWriter writer = new BufferedWriter(...)) {
    // Use the writer here
} // The writer is auto-closed here

这样,您可以使用Throwable.getSuppressed 与主体中的异常分开处理关闭时的异常。

【讨论】:

    【解决方案2】:

    取决于设计。你也可以试试

    try{
        try{
          //write to file
        }finally{
           aBufferedWriter.close();
        }
    }catch(IOException e){
    }
    

    如果你想抛出异常,为什么还要捕获它。

    【讨论】:

    • 我只是展示了不同的 try-catch 模式。异常处理显然取决于他打算如何处理捕获的异常。
    【解决方案3】:

    问。在下面的代码sn-p中,如果ex1被抛出,会被第二个catch块捕获,还是被扔回给方法的调用者?

    不,它不会被finally 中的catch 块捕获,前提是finally 块中没有异常,因此异常ex1 将被抛出回调用者方法。


    问。而如果被抛回给调用者,然后在finally块(ex2)中出现第二个异常,是不是意味着2个异常会被抛回给调用者(ex1和ex2)?

    在这种情况下,由于 finally 块中抛出异常,它将覆盖外部 catch 块中抛出的异常,并导致异常 ex2 被抛出回调用方方法。

    对于单次执行,只有其中一个异常会被抛回调用者方法,而不是两者。话虽这么说,有一个catch 块只是为了抛出已捕获的异常,真的没有意义。

    【讨论】:

      【解决方案4】:

      在 Java 7 之前,真正准确的模式是

      public void writeToFile(String file) throws IOException {
          IOException exception = null;
          OutputStream out = new FileOutputStream(file);
          try {
              // TODO: write data to file
          } catch (IOException ex) {
              // store exception for later rethrow
              exception = ex;
          } finally {
              try {
                  out.close();
              } catch (IOException ex) {
                  // do NOT supress 'outer' exception:
                  if (exception == null) {
                      exception = ex;
                  }
              }
          }
      
          if (exception != null) {
              throw exception;
          }
      }
      

      看起来很疯狂,但这涵盖了所有可能性并规避了异常抑制异常(当finally 语句中抛出异常时,它抑制了try 块中发生的“真实”异常 - 如果有的话)。

      但也许——为了可读性——你可以忍受被抑制的异常并这样做:

      OutputStream out = new FileOutputStream(file);
      try {
          // TODO: write data to file
      } finally {
          out.close(); // if an exception is thrown here, it hides the original exception
      }
      

      另见http://tutorials.jenkov.com/java-exception-handling/exception-handling-templates.html

      从 Java 7 开始,您可以(几乎)使用 try-with-resource 语句做同样的事情:

      public void writeToFile(String file) throws IOException {
          try (OutputStream out = new FileOutputStream(file)) {
          // TODO: write data to file
          }
      }
      

      请注意,关闭资源时引发的异常不会抑制原始异常。相反,这些额外的异常作为“抑制的异常”添加到基本异常中。您可以通过baseException.getSuppressed()(Java 7 及更高版本!)获取它们。

      另见http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-21
        • 2011-08-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多