是否有任何有理由忽略被捕获的exception?
哇,我刚刚从外包开发人员那里得到了一个C#的大型项目,在通过我的代码审查的同时,我的分析工具揭示了它被认为是不好的东西。 其中一个令人沮丧的信息是:
Exceptions.DontSwallowErrorsCatchingNonspecificExceptionsRule : 2106 defects
开发人员向我保证,他们对所有空的catch块有很好的理由,有时用空的catch块试一下就可以忽略无用的exception,并防止应用程序崩溃。 我觉得这是一个警察,完成学士学位。 我实际查找的一些例子是数据库调用,其中logging被保存到数据库,在这种情况下,如果忽略exception,用户将得到一个好的提示,认为一切正常,并继续他们的工作。 事实上,他们的工作从来没有得救。 我认为这绝对是最可怕的一种错误。 在这种情况下,他们完全错误的抛出代码尝试一个空的catch块。 但是我的问题是,“这种情况在任何情况下都可以接受吗?” 我想不是,但我知道是错的。
虽然有一些理由忽略例外, 但是,通常只有特定的例外情况才能安全地忽略。 正如康拉德·鲁道夫 ( Konrad Rudolph)所指出的那样,你可能不得不把错误作为一个框架的一部分。 正如osp70所指出的那样 ,可能会有一个你知道可以忽略的框架产生的exception。
然而,在这两种情况下,你都可能知道exceptiontypes,如果你知道types,那么你应该有类似于下面的代码:
try { // Do something that might generate an exception } catch (System.InvalidCastException ex) { // This exception is safe to ignore due to... } catch (System.Exception ex) { // Exception handling }
在你的应用程序的情况下,听起来像类似的东西可能适用于某些情况下, 但是你给的数据库保存的例子甚至在有exception时返回“OK”并不是一个好的标志。
除非我打算对他们做些什么,否则我不会收到例外。 忽视他们不是在做关于他们的事情。
我有时会使用一个非强制性的WebControl来显示页面。 如果失败,我不想阻止页面显示。 非关键WebControl的一个例子就是显示广告。
但是,我logging错误。 我只是不重新抛出它。
我的感觉是任何空的catch块都需要注释。
可能忽略某些错误是有效的,但是你需要logging你的理由。
另外,你不想把它作为一个通用的“catch(Exception e){}”。
您应该只捕获在那里预期的特定错误types,并且已知被安全地忽略。
一般不会,事实上在所有情况下99%都没有,但是
也有例外。 我所做的一个项目是使用第三方库处理TWAIN设备。 这是错误的,在一些硬件组合下会抛出一个空指针错误。 然而,我们从来没有发现任何情况下,它实际上并没有设法扫描文档之前 – 所以赶上例外是完全合理的。
所以我认为如果是你的代码抛出exception,那么你应该经常检查它,但是如果你被第三方代码困住,那么在某些情况下,你可能会被迫吃掉exception,继续前进。
另外一种情况是,你可以放弃捕捉和忽略exception,当你在进行unit testing的时候。
public void testSomething(){ try{ fooThatThrowsAnException(parameterThatCausesTheException); fail("The method didn't throw the exception that we expected it to"); } catch(SomeException e){ // do nothing, as we would expect this to happen, if the code works OK. } }
请注意,即使catch块什么都不做,它解释了为什么。
话虽如此,更新的testing框架(Junit4和TestNG)允许您指定预期的exception – 这导致类似这样的事情…
@Test(expected = SomeException.class) public void testSomething(){ fooThatThrowsAnException(parameterThatCausesTheException); fail("The method didn't throw the exception that we expected it to"); }
我想从我收集的最好的答案是它可以被接受,但应该是有限的。 您应该尝试使用另一种替代方法,如果找不到另一种替代方法,则应该足够了解代码的工作方式,以便您可以指定特定的exceptiontypes,而不是仅使用全部捕获所有“exception”。 logging这个例外被忽略的原因应包括在一个可理解的评论的forms。
在关键代码中,可能不会,因为程序的状态必须始终被精确定义。 就像你的数据库调用例子。
在非关键代码中,当然,我们也是这样做的(我们只是在消息框中显示捕获的exception并继续运行)。 也许一个插件或模块失败,但主程序不受影响。 也许一个lexical_cast失败,并有一个文字毛刺渲染到屏幕上。 没有必要停止这个过程。
我认为这可以接受的一个例子是在关键应用的一些非关键模块(例如,在航天飞机导航系统的声音反馈模块中),对于永远不应该发生的exception,并且不能更加干净地处理。
在这种情况下,你不希望让这个exception传播,导致整个应用程序失败(对不起,没有更多的导航系统,我们的哔哔声模块崩溃了,而且我们没有办法做到这一点)。
编辑说,在任何这些情况下,你至less要logging事件的地方。
我认为,如果你有一个空的catch块,你需要logging为什么它是空的,以便下一个开发人员知道。 例如在server.transfer有时会抛出一个webexception。 我明白这一点,并说我们可以忽略它,因为转移电话。
当然有些情况下可以捕获一个特定的exception并且什么也不做。 这是一个简单的例子:
public FileStream OpenFile(string path) { FileStream f = null; try { f = new FileStream(path, FileMode.Open, FileAccess.ReadWrite); } catch (FileNotFoundException) { } return f; }
你也可以这样写这个方法:
public FileStream OpenFile(string path) { FileStream f = null; FileInfo fi = new FileInfo(path); if (fi.Exists) { f = new FileStream(path, FileMode.Open, FileAccess.ReadWrite); } return f; }
在这种情况下,捕获exception是非常安全的,因为在检查文件存在与打开文件之间可能会删除文件。
有理由不这样做,当然。 在.NET中,exception在计算上是很昂贵的,所以你要避免引发大量的exception。 (在Python中,exception很便宜,使用exception来完成循环等操作是很常见的习惯用法。)
但是这忽略了一个特定的例外。 此代码:
catch { }
是不可原谅的。
没有很好的理由不去捕获try
块中的代码将抛出的特定types的exception。 这个天真的开发人员不pipetypes如何都能捕捉exception的第一个原因是,“但是我不知道可能抛出什么types的exception”,这是对这个问题的回答。
如果你不知道可能抛出什么types的exception,你不知道你的代码如何失败。 如果你不知道你的代码是如何失败的,那么你就没有理由认为只要继续处理就可以。
是的,在Maxim的职位某些情况下,它是可以接受的(不可避免的,必要的)。 那并不意味着你必须喜欢它。 2106违规可能是太多了,至less他们应该在catch块添加一个注释,为什么可以吞下这个exception。
@Dustin它不良的做法,以显示任何exception的细节,以公共用户(堆栈轨迹,行号等)。 您应该loggingexception并显示一个通用错误。
当涉及到例外时, 总是有例外 。
这取决于框架。 执行不力的框架可能实际上需要这个。 我记得VB6中的一个黑客,在那里无法确定一个集合是否包含一个元素。 唯一的方法是尝试检索元素并吞下错误。
我认为原来的问题已经得到了很好的回答,但是我想补充一点,如果你认为这些外包/签约的开发人员生产质量差的工作,你应该确保你公司的合适人员知道这个问题。
可能会有退货的机会,可能会部分隐瞒付款,或者同一家公司不会再使用。 如果你的公司再次使用承包商,他们可能会find一种方法来build立质量要求的协议,假设不是在那里。
如果这是内部工作,那么会产生不合格工作的团队/个人的后果。 也许这意味着他们不得不在夜晚和周末上class来解决这个问题,但是他们会以这样或那样的方式来解决问题。 这同样适用于承包商,甚至可能更是如此。
只要小心地解释你的职位,专注于什么是最好的公司/产品。 你不希望它看起来像你只是抱怨,或者你有某种政治反对外包。 不要为了你而做。 做到成本,上市时间,客户满意度等等。你知道,pipe理types关心的所有事情。
我很怀疑这个具体的一个。
Connection con = DriverManager.getConnection(url, "***", "***"); try { PreparedStatement pStmt = con.prepareStatement("your query here"); ... // query the database and get the results } catch(ClassNotFoundException cnfe) { // real exception handling goes here } catch(SQLException sqle) { // real exception handling goes here } finally { try { con.close(); } catch { // What do you do here? } }
我终于知道该怎么做最后一个在最后的块。 我从来没有见过close()之前抛出exception,这是不太可能的,我不担心它。 我只是loggingexception,继续前进。
除非你的catch代码也会
- loggingexception
- 将exception重新打包为另一个与相同抽象匹配的exception。 并再次抛出
- 以您认为合适的方式处理exception
您可以忽略该exception,但至less在方法文档中提到预期的exception,以便消费者可以根据需要进行预期和处理
从Java世界中可以忽略exception的例子来看:
String foo="foobar"; byte[] foobytes; try { foobytes=foo.getBytes("UTF-8"); } catch (UnsupportedEncodingException uee) { // This is guaranteed by the Java Language Specification not to occur, // since every Java implementation is required to support UTF-8. }
这就是说,即使在这样的情况下,我也经常使用
... catch (UnsupportedEncodingException uee) { // This is guaranteed by the Java Language Specification not to occur, // since every Java implementation is required to support UTF-8. uee.printStackTrace(); }
如果虚拟机将会疯狂/破坏性的,那么我就无能为力了,但是随着堆栈的跟踪,我至less会注意到它开始疯狂的下降了。
这是一件非常糟糕的事情。
虽然有正当的理由,你可能会忽略exception – 如果它是以某种方式预期的,并且没有必要做任何事情 – 但是做2000次似乎他们只是想把它们的例外扫到地下。
吞下exception的地方的例子可能是探测事情……你发送消息给某个设备或模块,但是你不关心它是否真的到达那里。
以下仅适用于已检查exception的语言,例如Java:
有时候,一个方法会抛出一个你不知道会发生的检查exception,例如,一些java API需要一个编码名称作为string,如果给定的编码不被支持,则抛出一个UnsupportedEncodingExceptionexception。 但通常我会传递一个我知道支持的字面“UTF-8”,所以我理论上可以在那里写一个空的catch。
而不是这样做(空捕获)我通常会抛出一个通用的非检查exception包装“不可能”的exception,或者我甚至宣布我抛出一个类ImpossibleException。 因为我对这个错误情况的理论是不可能的,所以我不希望这个例外被吞噬。
我喜欢让几乎所有的exception冒泡到一个应用程序处理程序,在这些应用程序处理程序中logging它们,并向最终用户显示一条通用的错误消息。 但是这里要注意的是,实际上不应该有很多例外。 如果您的应用程序抛出了许多exception,那么可能是错误的或者可能编码得更好的东西。 大多数情况下,我试图确保我的代码在高级中检查exception情况,因为生成exception很昂贵。
顺便说一句,外包编码通常是一个坏主意。 根据我的经验,通常他们只是薪水的顾问,对项目的成功没有任何影响。 另外,你也放弃了自己的编码标准(除非你把它包含在合同中)。
想想这样 – 如果你花费CPU周期来捕捉exception,然后吞咽,你忽略了一个潜在的问题,并浪费CPU。 正如许多人所说的,除非你的东西构造不好,否则应用程序不应该抛出许多例外。
我们有一个代表其他应用程序进行大量处理的应用程序,您可以在其中插入一些作业(configuration文件集合)到数据库中,应用程序将在适当的时候运行它。 我们倾向于在该应用程序中吞下很多例外情况,因为即使Job1以可怕的方式死亡并带来灾难性错误,我们也希望应用程序保持活跃状态,以便对Job2进行处理。
我认为最好的经验法则是,如果你完全意识到exception的意义和可能的后果,那么只能忽略一个例外。 在一些不影响系统其余部分的独立模块的情况下,我认为只要捕获genericsexception就可以了,只要你知道其他什么都不发生。
国际海事组织是更容易知道在Java的分歧,因为每个方法是需要声明所有exception它可以抛出,所以你知道什么期望,但在C#中,即使它没有logging的exception可以抛出,所以很难知道所有一个方法可能会抛出的exception,缺乏这方面的知识通常都是一个不好的主意。