【问题标题】:Can I avoid such cumbersome try...catch block我可以避免这种繁琐的 try...catch 块吗
【发布时间】:2011-03-19 08:06:13
【问题描述】:

通常在处理Java IO代码的时候,这里是我写的

    FileOutputStream out = null;
    try
    {
        out = new FileOutputStream("myfile.txt");
        // More and more code goes here...
    }
    catch (Exception e)
    {
    }
    finally 
    {
        // I put the close code in finally block, to enture the opened
        // file stream is always closed even there is exception happened.
        if (out != null) {
            // Another try catch block, troublesome.
            try {
                out.close();
            } catch (IOException ex) {
            }
        }
    }

如您所见,当我尝试关闭文件流时,我需要处理另一个 try...catch 块。

看起来很麻烦:(

有什么办法可以避免吗?将关闭代码放在非finally块中我觉得不舒服,因为其他代码引起的异常不会让“关闭”被调用。

【问题讨论】:

标签: java


【解决方案1】:

讨论于

Try-catch-finally and then again a try catch

Is there a preference for nested try/catch blocks?

基本上,问题是close() 异常是否值得捕获。

【讨论】:

    【解决方案2】:

    我倾向于为此使用实用函数:

    public static void safeClose(OutputStream out) {
      try {
        out.close();
      } catch (Exception e) {
        // do nothing
      }
    }
    

    将代码更改为更可口:

    FileOutputStream out = null;
    try {
      out = new FileOutputStream("myfile.txt");
      // do stuff
    } catch (Exception e) {
      // do something
    } finally {
      safeClose(out);
    }
    

    至少在 Java 7 之前,你不能在 Java 中做得更好,届时(希望)ARM ("Automatic Resource Management") blocks 会有所帮助。

    【讨论】:

    • ARM 块?我可以知道那是什么吗?
    • 一些指向安全关闭。你也应该检查空指针,对吧?
    • @Yah 在帖子中添加了一个关于 ARM 块的链接。至于检查null,你可以,但这在很大程度上是多余的。如果你抛出一个NullPointerException,它无论如何都会被catch 子句捕获。当然,如果您愿意,您可以添加该检查。
    • "catch (Exception e)" 不好,因为它会掩盖运行时异常,这些异常会导致进程终止或被显式处理(并且不太可能)。检查 null,捕获检查的异常是更好的方法。
    【解决方案3】:

    在 finally 中关闭流非常重要。您可以使用实用方法简化此过程,例如:

    public static void closeStream(Closeable closeable) {
        if(null != closeable) {
          try {
            closeable.close();
          } catch(IOException ex) {
            LOG.warning("Failed to properly close closeable.", ex);
          }
        }
      }
    

    我认为至少记录一个流关闭失败。那么用法就变成了:

    FileOutputStream out = null;
    try
    {
        out = new FileOutputStream("myfile.txt");
        // More and more code goes here...
    }
    catch (Exception e)
    {
    }
    finally 
    {
        closeStream(out);
    }
    

    在 Java 7 中,我相信流会自动关闭,并且对此类块的需求应该是多余的。

    【讨论】:

    • 从我在 SO 上听到的消息来看,Java 7 也会在潮湿的地方睡觉。
    • 您的意思是“catch (IOException e)”而不是“catch (Exception e)”吗?
    • 这是用户提出问题的原始示例代码的剪切粘贴。但是是的,它应该是 IOException。
    • +1 我唯一想说的是,我喜欢将 LOG 作为参数传递给 closeStream(),因为日志错误可能应该在日志中与调用者相关联。不是很重要,尤其是@warn,但我喜欢保持日志整洁。
    【解决方案4】:

    Automatic Resource Management 将出现在 Java 7 中,它将自动提供对此的处理。在那之前,OutputStreamInputStream 等对象自 Java 5 起就实现了Closeable 接口。我建议你提供一个实用方法来安全地关闭它们。这些方法通常会吃异常,因此请确保仅在您想忽略异常时使用它们(例如在 finally 方法中)。例如:

    public class IOUtils {
        public static void safeClose(Closeable c) {
            try {
                if (c != null)
                    c.close();
            } catch (IOException e) {
            }
        }
    }
    

    注意close()方法可以多次调用,如果已经关闭后续调用将没有效果,所以在try块正常运行时也提供一个close调用,不会忽略异常. From the Closeable.close documentation:

    如果流已经关闭,则调用此方法无效

    所以在代码的常规流中关闭输出流,safeClose 方法只会在 try 块中出现失败的情况下执行关闭:

    FileOutputStream out = null;
    try {
        out = new FileOutputStream("myfile.txt");
        //... 
        out.close();
        out = null;
    } finally {
        IOUtils.safeClose(out);
    }
    

    【讨论】:

      【解决方案5】:

      编写如下所示的方法;从你的 finally 块调用...

      static void wrappedClose(OutputStream os) {
        if (os != null) {
          try {
            os.close();
          }
          catch (IOException ex) {
             // perhaps log something here?
          }
        }
      

      【讨论】:

        【解决方案6】:

        Project Lombok 提供了一个 @Cleanup 注释,它消除了对 try catch 块的需要。 Here's an example.

        【讨论】:

          【解决方案7】:

          将你的 try/catch 和 try/finally 块分开。

          try
          {
              FileOutputStream out = new FileOutputStream("myfile.txt");
              try
              {
                  // More and more code goes here...
              }
              finally 
              {
                  out.close();
              }
          }
          catch (Exception e)
          {
              //handle all exceptions
          }
          

          外部的 catch 也可以捕捉到 close 抛出的任何东西。

          【讨论】:

          • 在 try 块中放入的代码越多,就越难以正确的方式处理异常。
          • 添加到 try 块的唯一代码是 out.close()。我认为由此引发的错误可能需要像创建或使用 out 引起的任何错误一样处理。
          猜你喜欢
          • 2016-04-14
          • 2015-01-02
          • 2011-02-11
          • 1970-01-01
          • 1970-01-01
          • 2018-06-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多