it-swarm.cn

可以使用空的catch语句吗?

我考虑了一下,无法提出一个例子。为什么有人要捕获异常却什么也不做呢?你能给个例子吗?也许这只是不应该做的事情。

61
ysolik

我一直都在处理D中的转换错误之类的事情:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

就是说,我认为所有catch块中都应带有某物,即使某些内容只是解释为什么的注释,您也忽略了该异常。

编辑:我还想强调一点,如果您要执行类似的操作,则应注意仅捕获要忽略的特定异常。做简单的catch {}几乎总是一件坏事。

78
dsimcha

我认为可以在不做任何事情甚至记录异常的情况下吞下异常就可以的一个示例是在记录代码本身内部。

如果您尝试记录某些内容并遇到异常,则您无能为力:

  • 您当然不能登录;
  • 您也许可以使用备用日志记录机制,但是大多数应用程序并不那么复杂,对于足够复杂的应用程序,备用日志记录机制会出现相同的设计问题;
  • 快速失败-对于大多数应用而言,这将是一个过于彻底的解决方案;
  • 抛出异常并没有多大用处,因为它将最终导致堆栈中的catch语句,几乎可以肯定地尝试记录它。

这给您留下了“轻描淡写”的选项,可以悄悄地吞下它,使应用程序能够继续执行其主要任务,但是却损害了对其进行故障排除的能力。

50
kdubinets

如果无论如何可选操作都会引发异常,则可能无事可做。记录它可能没有用。在这种情况下,您可能只想抓住它而什么也不做。

如果执行此操作,请添加评论。始终注释任何看起来像错误的内容(_switch语句的空缺,_catch块为空,条件中的赋值)。

您可能会争辩说这不是对异常的正确使用,但这是另一个问题。

8
David Thornley

在某些情况下,Java要求您处理绝对不可能发生的异常。请考虑以下代码:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

Java平台的每个实现都需要支持以下标准字符集。

...

UTF-8

在不破坏Java)平台的情况下,根本没有办法导致此异常。那么,为什么要麻烦处理它呢?.

6
user281377

作为一般规则,不可以。您要么将异常抛出堆栈,要么记录发生的事情。

但是,在解析字符串并将其转换为数字时,我经常这样做(尤其是在映射具有一次性使用功能并丢弃各种功能的项目中)。

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;
6
Fil

catch块是大多数语言中的代码味道。主要思想是在异常情况下使用异常,而不是将其用于逻辑控制。所有异常必须在某处处理。

采用这种方法的结果是,在对一个特定的应用程序层进行编程时,您有多种选择:

  • 对异常不做任何事情。它将被另一层捕获和处理
  • 抓住并执行纠正措施。
  • 抓住它,做点什么,但是将它重新扔给另一层处理

这实际上并没有为空的catch块留任何空间。

编辑后添加:假设您正在使用一种语言,其中抛出异常是控制程序逻辑的常规方法(goto的替代方法之一)。然后,用这种语言编写的程序中的空catch块非常类似于传统语言中的空else块(或根本没有else块)。但是,我相信这不是C#,Java或C++开发社区)推荐的编程风格。

6
azheglov

在某些情况下,该异常并非完全例外。实际上,这是预料之中的。考虑以下示例:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

由于Java.lang.Process()中没有isAlive()方法,因此检查它是否仍然存在的唯一方法是调用exitValue(),如果该进程仍在运行,则将抛出IllegalThreadStateException。

3
user281377

以我不起眼的经验,这很少是好事。您的里程可能会有所不同。

几乎每次我在我们的代码库中看到此内容时,都是因为我已经找到了一个可食异常已隐藏的错误。换句话说,通过不提供任何代码,应用程序无法指示错误或执行其他操作。

有时,例如在API层,您可能不希望或无法让异常过去,因此在这种情况下,我倾向于尝试捕获最通用的异常,然后将其记录下来。再一次,至少给调试/诊断会话一个机会。

通常,如果必须为空,则我所做的至少是放置某种断言,因此至少在调试会话期间会发生某些情况。就是说,如果我不能处理,我倾向于完全忽略它们。

2
DevSolo

IMO在一个地方可以使用空catch语句。在预期例外的测试案例中:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}
2
Victor Hurdugaci

我相信在某些情况下有一个空的catch子句是合理的-这些情况是您希望代码在特定操作失败的情况下继续运行的情况。但是,我确实认为这种模式很容易过度使用,因此应仔细检查每次使用,以确保没有更好的方法来处理它。特别是,如果它使程序处于不一致状态,或者以后可能导致代码的其他部分失败,则永远不要这样做。

2
o. nate

存在检查是一个很好的用例:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

另一种情况是使用finally子句:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

有人建议在ECMAScript中允许 省略catch绑定 ,这与该用例和类似用例有关。

参考文献

1
Paul Sweatte

我不相信发生异常时不会发出某种程度的警报-编程的目标之一不应该是改善代码吗?如果10%的时间发生异常,而您却一无所知,那么异常总是那么糟糕,甚至更糟。

但是,我确实看到了另一面,如果异常在代码处理中没有真正的危害,那么为什么还要让用户接触它。我通常实现的解决方案是由记录器类(即我在工作中编写的每个类中)记录它。

如果这是一个良性异常,那么我将调用Logger的.Debug()方法;否则,Logger.Error()(并且(可能)抛出)。

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

顺便说一句,在我的记录器实现中,仅当我的App.Config文件指定程序执行日志级别处于“调试”模式时,对.Debug()方法的调用才会记录该日志。

1
Tim Claason

在某些情况下,无论最关键的部分放在最后,都必须执行某些顺序是可以的。

例如。在主机与控制器的运动控制通信中。在紧急情况下,有许多准备步骤来中止运动,停止轨迹生成,使电动机减速,启用中断,禁用放大器,然后必须关闭总线电源。所有步骤必须按顺序进行,并且如果其中一个步骤失败,则即使存在公认的损坏硬件风险,也必须执行其余步骤。说,即使以上所有方法都失败了,仍然必须关闭总线电源。

0
user7071

我真正需要做的事情只有一次是使用控制台应用程序的日志记录类。有一个顶级全局捕获处理程序,该处理程序将错误发送到STDOUT,将错误记录到文件中,然后使用> 0错误代码关闭应用程序。

这里的问题是有时记录到文件失败。目录权限使您无法写文件,该文件被独占锁定,无论如何。如果发生这种情况,我将无法像在其他地方一样处理异常(捕获,记录相关详细信息,包装更好的异常类型等),因为记录异常详细信息会导致记录器进行已经失败的相同操作(尝试写入文件)。当他们再次失败时...您会看到我要去的地方。它陷入无限循环。

如果删除了一些try {}块,则最终可能会在消息框中显示异常(而不是无声配置应用程序所需的异常)。因此,在写入日志文件的方法中,我有一个空的catch处理程序。这不会掩埋错误,因为您仍然会得到> 0错误代码,它只是停止了无限循环并允许应用正常退出。

当然有一条评论,解释为什么它是空的。

(我本来打算早些发布,但是我只是害怕被遗忘。因为我不是唯一的一个...)

0
JohnL

正常关闭系统资源以从错误中恢复

例如。如果您在后台运行的服务没有向用户提供反馈,则可能不希望向用户推送错误指示,但是do需要关闭资源被优雅地使用。

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

理想情况下,您可以在调试模式下使用catch来捕获错误并将错误打印到控制台或日志文件中以进行测试。在生产环境中,通常期望后台服务在引发错误时不会中断用户,因此应抑制错误输出。

0
Evan Plaice