在try-catch块中放入多少代码

时间:2013-10-24 15:10:31

标签: java try-catch

try/catch区块内放置多少代码是否有“最佳做法”?

我在下面发布了3个不同的场景。

我没有在每个catch块中包含行为,并且我没有包含finally块。这是为了提高观众的可读性。假设每个catch做不同的事情。并假设finally将关闭流。试着为未来的读者创建一个易于阅读的例子。

  1. 控制,没有try/catch
  2. 每个地方需要1 try/catch的代码。
  3. 仅包含1 try/catch整个代码块的代码。
  4. 通常认为什么是最佳做法?为什么?


    情景1

    没有try/catch的代码,仅用于控制。

        BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            Object object = new Object();
            this.doSomething(object);
        }
        bufferedReader.close();
    

    场景2

    为每个需要的地方添加try/catch块的代码。

        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new FileReader("somepath"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        String line;
        try {
            while ((line = bufferedReader.readLine()) != null) {
                Object object = new Object();
                this.doSomething(object);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    

    场景3

    围绕整个代码块的1 try/catch代码。

        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                Object object = new Object();
                this.doSomething(object);
            }
            bufferedReader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    

10 个答案:

答案 0 :(得分:14)

您应根据以下标准确定尝试/捕获的范围:

  • 您是否需要根据来执行不同的事情
  • 你是否需要根据抛出哪个异常来做不同的事情
  • 抛出给定异常时需要跳过哪些代码(又名“无效”)?

回答这些问题将使您能够确定任何try / catch块的适当范围。

答案 1 :(得分:5)

我尽可能少地使用try-catch。

这使您可以非常轻松地将代码片段移动到单独的方法中,这是一种很好的编码实践(遵守单一责任原则;请参阅Robert C. Martin撰写的“清洁代码:敏捷软件工艺手册”一书)。 / p>

另一个优点是您可以快速识别哪些代码实际上可以引发异常。

场景2看起来有点极端,而且由于方法非常小,因此场景3似乎是最佳选择。

但是,您需要在finally块中使用“close”语句。

答案 2 :(得分:2)

这是一个意见问题。我已经看到了很多这些模式。

模式1只有当你的方法可以抛出激活并且具有调用者链处理的​​东西时才有用。这通常是可取的。但是,由于close调用不在finally block中,因此可能不会调用它。至少,使用try-finally块。

模式2不好,因为如果第一个try-catch块处理异常,则该方法的其余部分是无用的。

模式3没问题,但不是很好,因为打印堆栈跟踪隐藏了操作失败的事实。如果调用者认为操作没有发生,他将做什么。此外,close可能没有发生,这可能导致程序失败。

在伪代码中,模式3的这种变体更好:

Declare Streams, connections, etc.
try
    Initialize streams, connections, etc,
    Do work.
catch (optional)
    Catch and handle exceptions.
    Do not simply log and ignore.
finally
    Close connections and streams in reverse order.
    Remember, closing these objects can throw,
        so catch exceptions the close operation throws.
End.

如果您使用的是Java 7,请使用try-with-resources:

try (BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"))) {
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
}

IOException冒泡到来电者。

答案 3 :(得分:1)

你应该采用第三种方案。

如果bufferedReader遇到异常,那么在第二个场景中创建时,你尝试readLine()就会遇到异常,它会遇到另一个异常。没有必要为同一个问题提出多个例外。

您还应该关闭finally块中的bufferedReader。

BufferedReader bufferedReader;
try {
    bufferedReader = new BufferedReader(new FileReader("somepath"));
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (bufferedReader != null)
        bufferedReader.close(); 
}

答案 4 :(得分:1)

我认为Exception非协作返回的结果类型。因此,当我使用try-catch部分时,我正在尝试回答问题

  1. 我应该在这里处理意外结果还是应该在更高层次上传播?
  2. 我应该处理哪些意想不到的结果?
  3. 如何处理它们?
  4. 在95%的情况下,我没有比第一点更进一步,所以我只是传播错误。

    对于文件处理,我使用try-with-resources重新抛出IOException throw new RuntimeException(e)

答案 5 :(得分:0)

我认为这与在方法中放入多少代码类似。尝试编写try / catch / finally,它只需要一个屏幕。我想说将整个方法体包装到try {}块中并不是一个问题,但如果它变得太长,你应该把这个代码分成几个方法。

答案 6 :(得分:0)

你有一个try / catch的例子没有意义,因为你只是打印一个堆栈跟踪并继续 - 已经知道它将是一个失败。你也可以尝试/捕获整个批次,或者添加抛出SomeException到方法签名,并让调用方法决定出了什么问题。

另外,不要担心在try / catch中挤压太多。您始终可以将该代码提取到另一个方法中。可读性是编程中最重要的一个方面。

答案 7 :(得分:0)

第三种选择当然是最好的。你不希望你的try / catch块变得笨拙,但在这个例子中,它足够短,你不需要像在第二个选项中那样划分它。

答案 8 :(得分:0)

不是场景2.如果FileReader或BufferedReader构造函数抛出,则bufferedReader将为null,但下一个try / catch仍将执行。因此,您将在bufferedReader.readLine中获得(未捕获)异常 - 一个NullPointerException。在场景1和场景3之间,我通常更喜欢3个,因为它不需要调用者捕获。顺便说一下,你不需要显式地捕获FileNotFoundException,因为它继承自IOException,因此catch块会捕获它们。

答案 9 :(得分:0)

jtahlborn已经有了正确答案。

不幸的是,有时候,正确的异常处理可能非常繁琐。 如果需要,应该准备好处理它。

另一种可能的情况是嵌套的try-catch块。

考虑:

BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
try {
        String line;

        while ((line = bufferedReader.readLine()) != null) {
            Object object = new Object();
            try {
               this.doSomething(object);
            } catch (InvalidArgumentException iae) {
               throw new RuntimeErrorException("Failed to process line " + line + ", iae);
            } catch (ParserWarning e) {
               e.printStackTrace();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        bufferedReader.close();
    }