【问题标题】:Should multiple Try/Catch blocks in a method be combined是否应该组合方法中的多个 Try/Catch 块
【发布时间】:2011-05-09 19:26:08
【问题描述】:

查看我的方法,我不确定是否必须使用三个单独的 try/catch 块。我应该对整个方法使用唯一的一个吗?什么是好的做法?

public void save(Object object, File file) {    

        BufferedWriter writter = null;

        try {
            writter = new BufferedWriter(new FileWriter(file));
        } catch (IOException e) {
            e.printStackTrace();
        }

        Dictionary dictionary = (Dictionary)object; 
        ArrayList<Card> cardList = dictionary.getCardList();
        for (Card card: cardList) {
            String line = card.getForeignWord() + " / " + card.getNativeWord();
            try {
                writter.write(line);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            writter.flush();
            writter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

【问题讨论】:

    标签: java


    【解决方案1】:

    我更喜欢编写两个 try 块,一个用于 finally,一个用于 catch。由于它的编写方式,您永远不会将 writter 设置为 null,也不必在关闭时检查 null。唯一的问题是关闭时的异常会在处理时隐藏异常,但如果您想以不同的方式处理这两个异常,这只是一个问题。

    public void save(Object object, File file) {
        try {
            BufferedWriter writter = new BufferedWriter(new FileWriter(file));
            try {
                Dictionary dictionary = (Dictionary)object; 
                ArrayList<Card> cardList = dictionary.getCardList();
                for (Card card: cardList) {
                    String line = card.getForeignWord() + " / " + card.getNativeWord();
                    writter.write(line);
                }
            } finally {
                writter.flush();
                writter.close();
            }
        } catch (IOException e) {
            e.printStackTrace(); //Or something more useful
        }
    }
    

    【讨论】:

      【解决方案2】:

      在 I/O 的特定情况下,我建议您查看一些可用的常用库,例如​​ Guava 和 Jakarta commons。他们有一些很好的脚本来执行静默关闭。

      例如Commons IO IOUtils

      这些可以清理你的代码很多

      【讨论】:

        【解决方案3】:

        您当然不想要三个单独的代码块。在第一个块中,您在设置 writer 时遇到了错误,但在随后的块中,您使用 writer,如果第一个块失败,这将毫无意义。当发生 I/O 错误时,您最终会抛出 NullPointerException — 这并不理想。 :-)

        这些东西有很大的风格空间,但这是对您的功能的相当标准的重新解释。它只使用了两个块(尽管您可以选择添加第三个;请参阅代码中的 cmets):

        public void save(Object object, File file) {    
        
            BufferedWriter writter = null;
        
            try {
                writter = new BufferedWriter(new FileWriter(file));
        
                Dictionary dictionary = (Dictionary)object; 
                ArrayList<Card> cardList = dictionary.getCardList();
                for (Card card: cardList) {
                    String line = card.getForeignWord() + " / " + card.getNativeWord();
                    writter.write(line); // <== I removed the block around this, on
                                         // the assumption that if writing one card fails,
                                         // you want the whole operation to fail. If you
                                         // just want to ignore it, you would put back
                                         // the block.
                }
        
                writter.flush(); // <== This is unnecessary, `close` will flush
                writter.close();
                writter = null;  // <== null `writter` when done with it, as a flag
            } catch (IOException e) {
                e.printStackTrace(); // <== Usually want to do something more useful with this
            } finally {
                // Handle the case where something failed that you *didn't* catch
                if (writter != null) {
                    try {
                        writter.close();
                        writter = null;
                    } catch (Exception e2) {
                    }
                }
            }
        }
        

        注意finally 块:在这里,您可能正在处理正常情况(在这种情况下,writter 将是null),或者您可能正在处理您没有捕获的异常(这是'不寻常,异常的要点之一是处理此级别的适当内容并将其他任何内容传递给调用者)。如果writter!null,则关闭它。当你关闭它时,任何发生的异常,否则你会掩盖原来的异常。 (对于这种情况,我有在吃异常的同时关闭东西的实用功能。对我来说,这可能是writter = Utils.silentClose(writter); [silentClose 总是返回null])。现在,在这段代码中,您可能不会期待其他异常,但是 A)您可以稍后更改它,并且 B)RuntimeExceptions 可以在任何时候发生。最好习惯使用该模式。

        【讨论】:

        • @AndroidNoob:别担心!很高兴有帮助。
        • @T.J. Crowder 为什么要在 try 块内关闭 writer?是不是多余的?
        • @Andrew: “这不是多余的吗?” 不,因为当我在 finally 块中关闭它时,我会吃掉(抑制)任何发生的异常关闭它。当我在主块中关闭它时,我不会 - 因为如果它抛出我希望它传播。这只是一种方法;另一个是检查某种成功/失败标志;另一个是有一个最终的catch 捕获一切,进行静默清理,然后重新抛出。我通常发现在主块中进行关闭更简单,尤其是。因为我有实用功能来进行静音关闭,使它们成为单线。
        • @T.J.克劳德谢谢,现在我明白你的意思了!以前我使用了挂起的异常习语,在这里描述:stackoverflow.com/questions/884007/…(忽略所有Closeables 管理)虽然我没有将它包装到一个单独的类中。我最终得到这样的代码:gist.github.com/676312 它与您的习语相比如何?哦,你为什么在 finally 块中将 writer 设置为 null?
        • @Andrew:它看起来比我通常最终得到的要复杂,它突出了重新抛出异常的问题以及你重新抛出的异常类型。我不想将所有内容都转换为 RuntimeException s。这就是我通常编写的代码的样子:pastie.org/1298959 或更准确地说是pastie.org/1298961,甚至是pastie.org/1298962,如果我愿意依赖 HotSpot 中的动态内联。 :-)
        【解决方案4】:

        使用 try-catch,恐怕 'don't s' 比 'do's' 多......

        本文档列出了其中的一些:

        http://today.java.net/article/2006/04/04/exception-handling-antipatterns

        尽管如此,还是有一些事情要做,我觉得这很有趣:

        http://www.wikijava.org/wiki/10_best_practices_with_Exceptions

        【讨论】:

          【解决方案5】:

          这是一个品味问题 - 没有正确的答案。

          就个人而言,我更喜欢一个 try/catch 块。如果我看到很多,我开始担心我的方法做得太多并且变得太大。这表明可能是时候将其分解为更小的方法了。

          我会这样写这个方法:

          public void save(Object object, File file) throws IOException
          {
          
              BufferedWriter writer  = null;
          
              try {
              writer = new BufferedWriter(new FileWriter(file));
          
              Dictionary dictionary = (Dictionary) object;
              ArrayList<Card> cardList = dictionary.getCardList();
              for (Card card : cardList)
              {
                  String line = card.getForeignWord() + " / " + card.getNativeWord();
                  writer.write(line);
              }
              }
              finally
              {
                  IOUtils.close(writer); 
              }    
          }
          

          我有一个 IOUtils 类来封装流、读取器和写入器的正确关闭。您将一次又一次地编写该代码。如果我不介意另一个依赖项,我会将其作为类中的静态方法作为单行方法 - 或者使用 Apache Commons IO Utils JAR。

          【讨论】:

          • 确实没有正确答案,但恕我直言,这不仅仅是品味
          • 同意,彼得。还有try/finally等问题。
          【解决方案6】:

          什么是好的取决于您的代码打算做什么。例如,第二个 try/catch 在一个循环中,这意味着它会处理列表中的所有cards,即使其中一个处理失败。如果您对整个方法使用一个try/catch,则此行为将被更改。如果您的算法允许,请使用 try/catch

          【讨论】:

            猜你喜欢
            • 2021-06-16
            • 1970-01-01
            • 1970-01-01
            • 2018-07-24
            • 2022-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-08
            相关资源
            最近更新 更多