java try块应该尽可能紧密地限定范围吗?

时间:2010-04-13 23:13:48

标签: java exception-handling readability

我被告知使用Java try-catch机制会有一些开销。因此,虽然有必要在try块中放置抛出checked异常的方法来处理可能的异常,但是在性能方面优化的是限制try块的大小以仅包含那些可能抛出异常的操作。

我不太确定这是一个明智的结论。

考虑以下两个实现处理指定文本文件的函数。

即使第一个产生了一些不必要的开销,我发现它更容易理解。仅通过查看陈述来确定异常的确切位置尚不清楚,但评论清楚地表明哪些陈述是负责的。

第二个比第一个更长更复杂。特别是,必须修改第一个很好的读行习惯用法以使readLine调用符合try块。

在函数中处理异常的最佳做法是什么?在定义中可能抛出多个异常?

这个包含try块中的所有处理代码:

void processFile(File f)
{
  try
  {
    // construction of FileReader can throw FileNotFoundException
    BufferedReader in = new BufferedReader(new FileReader(f));

    // call of readLine can throw IOException
    String line;
    while ((line = in.readLine()) != null)
    {
      process(line);
    }
  }
  catch (FileNotFoundException ex)
  {
    handle(ex);
  }
  catch (IOException ex)
  {
    handle(ex);
  }
}

这个只包含在try块中抛出异常的方法:

void processFile(File f)
{
  FileReader reader;
  try
  {
    reader = new FileReader(f);
  }
  catch (FileNotFoundException ex)
  {
    handle(ex);
    return;
  }

  BufferedReader in = new BufferedReader(reader);

  String line;
  while (true)
  {
    try
    {
      line = in.readLine();
    }
    catch (IOException ex)
    {
      handle(ex);
      break;
    }

    if (line == null)
    {
      break;
    }

    process(line);
  }
}

7 个答案:

答案 0 :(得分:45)

这里的基本前提是 false: try块的大小对性能没有影响。性能受到在运行时实际引发异常的影响,并且与try块的大小无关。

但是,保持较小的试块可以带来更好的程序。

您可能会捕获恢复和继续的异常,或者您可能只是将它们报告给调用者(或通过某些UI向人类报告)。

在第一种情况下,您可以从中恢复的失败通常是非常具体的,这会导致较小的try块。

在第二种情况下,捕获异常以便它可以被另一个异常包装并重新抛出或显示给用户,小try块表示您更准确地知道哪个操作失败,以及进行该调用的更高级别的上下文。这允许您创建更具体的错误报告。

当然,这些指南有......例外(抱歉!)。例如,在某些情况下,非常具体的错误报告可能是安全问题。


了解try块对编译代码的影响可能很有用。它根本不会改变编译指令! (当然,相应的catch块确实如此,因为它就像任何其他代码一样。)

try块在与该方法关联的异常表中创建一个条目。该表具有一系列源指令计数器,异常类型和目标指令。引发异常时,将检查此表以查看是否存在具有匹配类型的条目,以及包含引发异常的指令的范围。如果是,则执行分支到相应的目标号码。

要实现的重要一点是,除非需要,否则不会查询此表(并且对运行性能没有影响)。 (忽略了加载课程的一点开销。)

答案 1 :(得分:11)

  

我被告知使用Java try-catch机制会有一些开销。

绝对。方法调用也有开销。但是你不应该把所有代码放在一个方法中。

不要过早使用优化号角,但重点应放在易于阅读,组织等方面。语言结构很少影响性能,就像系统组织和算法选择一样。

对我来说,第一个是最容易阅读的。

答案 2 :(得分:3)

没有。您应该考虑的唯一事情是您可以合理地处理异常以及需要回收的资源(最终)。

答案 3 :(得分:2)

这是最糟糕的过早优化。不要这样做。

“我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源” - Knuth。

答案 4 :(得分:1)

第二种方法的好处非常少。毕竟如果你能成功打开文件而不是从中读取文件,那么你的计算机就会出现问题。因此知道来自readLine()方法的io异常很少有用。如您所知,不同的问题也会抛出不同的异常(FileNotFoundException等)

只要你用'逻辑'块来限定它,即在1中打开,读取和关闭文件,我会选择第一种方法。它的读取要简单得多,特别是在处理IO时,try-catch开销使用的处理器周期最小(如果有的话)。

答案 5 :(得分:1)

将try块放在可能引发异常的特定代码周围,在我看来更容易阅读。您可能希望为每个错误显示不同的消息并向用户提供说明,具体取决于错误发生的位置。

但是,大多数人提到的性能问题与提升异常有关,而不是与try块本身有关。

换句话说,只要你没有引发错误,try块就不会明显影响性能。您不应该将try块视为另一个流控制构造,并引发错误以分支代码。这就是你想要避免的。

答案 6 :(得分:0)

第二种方法将生成reader可能尚未初始化的编译器错误。您可以通过将其初始化为null来解决这个问题,但这只意味着您可以获得NPE,并且没有任何优势。