【问题标题】:How much code to put in try-catch block [closed]在 try-catch 块中放入多少代码 [关闭]
【发布时间】:2013-10-24 15:10:30
【问题描述】:

对于在try/catch 块中放入多少代码是否有“最佳实践”?

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

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

  1. 控制,没有try/catch
  2. 每个需要的地方都用 1 个try/catch 编码。
  3. 整个代码块周围只有 1 个try/catch 的代码。

公认的最佳做法是什么?为什么?


场景 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();
    }

【问题讨论】:

  • 我认为最好为要捕获的异常放置一个 try 语句和多个捕获。更好的可读性。
  • 在场景 1 中,您是指方法本身在哪里throws IOException
  • @Vallentin Scenario 1 只是为了控制,基本无视。我只是想显示没有try/catch 块的代码。
  • @AliAlamiri 我同意Scenario 3 更容易阅读,但这是唯一的原因吗?
  • @prolink007 部分最佳实践与可读性有关。还有其他因素,这取决于代码本身和正在使用的内容(我的观点)。例如,场景 3 在其他场景中可能效果不佳。

标签: java try-catch


【解决方案1】:

我会尽可能少地尝试捕获。

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

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

场景 2 似乎有点极端,而且由于方法很小,场景 3 似乎是最好的选择。

但是,您需要在 finally 块中包含“关闭”语句。

【讨论】:

  • 我只是想创建一个示例。我没有包括每个捕获的行为,也没有包括最后。只是试图让这些示例非常容易让用户浏览。不想让信息过载。
  • 好的,有道理
【解决方案2】:

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

  • 您是否需要根据异常的来源做不同的事情?
  • 您是否需要根据抛出的异常做不同的事情?
  • 抛出给定异常时需要跳过哪些代码(也称为“无效”)?

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

【讨论】:

  • @Basilevs - 提到嵌套的具体内容?
  • 有些场景需要嵌套的 try catch 块,我认为小点可能会使这个答案更好。我可能错了——结构会被破坏。
  • @Basilevs - 嵌套的 try/catch 块是一种实现选择,与我上面提到的要点有关。回答这些问题应该会告诉您如何指定 try/catch 块(单/多/嵌套/等)。
【解决方案3】:

我认为Exception 是一个无条件返回的结果类型。因此,当我使用 try-catch 部分时,我会尝试回答问题

  1. 我应该在这里处理意外结果还是应该将其传播到更高级别?
  2. 我应该处理哪些意外结果?
  3. 如何处理?

在 95% 的情况下,我不会比第一点更进一步,所以我只是传播错误。

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

【讨论】:

    【解决方案4】:

    这是一个见仁见智的问题。我经常看到这些模式。

    仅当您的方法可以抛出异常并让调用者链处理该问题时,模式 1 才有效。这通常是可取的。但是,由于close 调用不在finally block 中,它可能不会被调用。至少,使用try-finally 块。

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

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

    在伪代码中,模式 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);
        }
    }
    

    IOExceptions 冒泡给来电者。

    【讨论】:

    • 我只是想创建一个示例。我没有包括每个捕获的行为,也没有包括最后。只是试图让这些示例非常容易让用户浏览。不想让信息过载。
    【解决方案5】:

    你应该选择第三种情况。

    如果 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(); 
    }
    

    【讨论】:

    • 我只是想创建一个示例。我没有包括每个捕获的行为,也没有包括最后。只是试图让这些示例非常容易让用户浏览。不想让信息过载。
    • 另外,close() 可以扔。
    【解决方案6】:

    我认为这与在方法中放入多少代码类似。尝试编写不超过一屏的 try/catch/finally。我想说把整个方法体封装到 try{} 块中是没有问题的,但是如果太长,你应该把这段代码分成几个方法。

    【讨论】:

      【解决方案7】:

      您的示例每个都尝试/捕获没有意义,因为您只是打印堆栈跟踪并继续 - 已经知道这将是一个失败。您不妨尝试/捕获全部内容,或者将 throws SomeException 添加到方法签名中,让调用方法来决定出了什么问题。

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

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            【解决方案10】:

            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();
                }
            

            【讨论】:

            • 是的,它很容易变得更加复杂。我只是想举一个简单的例子,便于其他观众阅读。
            猜你喜欢
            • 2016-07-02
            • 1970-01-01
            • 1970-01-01
            • 2015-09-23
            • 2020-04-02
            • 2016-03-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多