是否应合并方法中的多个Try / Catch块
看看我的方法,我不确定我必须使用三个单独的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 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(); } }
你当然不希望三个独立的块与代码一样。 在第一个块中,您正在捕获设置编写器的错误,但是在后续块中您正在使用 writer
,如果第一个块失败则没有意义。 当I / O错误发生时,你最终会抛出NullPointerException
– 不理想。 🙂
这个东西有很多风格,但这是对你的function的一个相当标准的重新解释。 它只使用两个块(尽管您可以选择添加第三个块;请参阅代码中的注释):
public void save(Object object, File file) { BufferedWriter writter = null; try { writter = new BufferedWriter(new FileWriter(file)); Dictionary dictionary = (Dictionary)object; ArrayList 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
),或者您可能正在处理您未捕获的exception(这不是不寻常的,这是例外情况是处理此级别的适当内容并将其他任何内容传递给调用者。 如果writter
为!null
,请将其关闭。 当你关闭它时, 吃任何发生的exception或你会掩盖原来的exception。 (对于这种情况,我有实用函数用于关闭事物,对于我来说,这可能是writter = Utils.silentClose(writter);
[ silentClose
总是返回null
])。 现在,在此代码中,您可能不会期望其他exception,但A)您可能稍后更改,并且B) RuntimeException
可以在任何时候发生。 最习惯使用该模式。
什么是好的取决于您的代码的目的。 例如,第二个try / catch位于循环内,这意味着它将处理列表中的所有card
,即使处理失败也是如此。 如果对整个方法使用一个try/catch
,则会更改此行为。 如果算法允许,请使用一次try/catch
。
这是一个品味问题 – 没有正确的答案。
就个人而言,我更喜欢一个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 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-catch,有更多’不要’而不是’做’我害怕…
本文件列出了其中一些:
http://today.java.net/article/2006/04/04/exception-handling-antipatterns
尽管如此,有一些事情在那里,我发现这很有趣:
http://www.wikijava.org/wiki/10_best_practices_with_Exceptions
在I / OI的特定情况下,建议您查看一些常用的库,例如Guava和Jakarta commons。 他们有一些很好的脚本来执行静默关闭。
例如Commons IO IOUtils
这些可以清理你的代码
我更喜欢写两个try块,一个用于finally,一个用于catch。 由于它的编写方式,您不会将writter设置为null,也不必在关闭时检查null。 唯一的问题是关闭时exception会在处理时隐藏exception,但如果您想以不同方式处理这两个exception,则只会出现问题。
public void save(Object object, File file) { try { BufferedWriter writter = new BufferedWriter(new FileWriter(file)); try { Dictionary dictionary = (Dictionary)object; ArrayList 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 } }