Java try块的范围应该尽可能紧密吗?

2022-09-01 02:01:43

有人告诉我,使用Java try-catch机制有一些开销。因此,虽然有必要将引发已检验异常的方法放在 try 块中以处理可能的异常,但从性能角度来看,最好将 try 块的大小限制为仅包含那些可能引发异常的操作。

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

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

即使第一个确实会产生一些不必要的开销,我发现它更容易遵循。仅仅通过查看声明就不太清楚例外究竟来自哪里,但注释清楚地表明了哪些声明是负责任的。

第二个比第一个更长,更复杂。特别是,第一个漂亮的行读习语必须被修改,以将呼叫放入尝试块中。readLine

在可能在其定义中引发多个异常的功能中处理异常的最佳实践是什么?

这个包含 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);
  }
}

这个只包含尝试块中引发异常的方法:

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

答案 1

这里的基本前提是错误的:块的大小在性能上没有区别。性能会受到在运行时实际引发异常的影响,这与块的大小无关。trytry

但是,保持较小的尝试块可以产生更好的程序。

您可能会捕获异常以进行恢复并继续,或者您可能只是为了向调用方(或通过某些 UI 向人类)报告它们。

在第一种情况下,可以从中恢复的故障通常非常具体,这会导致块变小。try

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

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


了解块对已编译代码的影响可能很有用。它根本不会更改已编译的指令!(当然,相应的块可以,因为它就像任何其他代码一样。trycatch

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

需要注意的重要一点是,除非需要,否则不会参考此表(并且对运行性能没有影响)。(忽略了类加载过程中的一点开销。


答案 2

有人告诉我,使用Java try-catch机制有一些开销。

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

不要过早地哄骗优化喇叭,但重点应该放在易读性,组织性等方面。语言构造很少像系统组织和算法选择那样影响性能。

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


推荐