这是一个通用的编程问题,而不是语言特定的。我已经看过几个appraoches尝试和捕获。
一个是对所需数据进行任何预处理,使用适当的参数调用函数并将其包装到try / catch块中。
另一种是简单地调用函数传递数据并依赖函数内的try catch,如果发生错误,函数返回true / false标志。
第三种是在函数外部和内部尝试捕获的组合。但是,如果函数尝试catch捕获某些东西,它会抛出函数外捕获的try catch块的另一个异常。
对这些错误控制方法的优缺点有什么想法,或者是否有可接受的标准?我的谷歌搜索技巧让我无法找到准确的数据。
答案 0 :(得分:17)
通常,只有在可以实际处理的情况下才能捕获异常。
除了记录异常之外没有任何目的捕获异常是没有意义的。例外情况是应该在“顶级”捕获异常,以便记录它。所有其他代码都应允许异常传播到将记录它们的代码。
答案 1 :(得分:4)
我认为考虑这个问题的最好方法是在程序状态方面。您不希望失败的操作损坏程序状态。 This paper描述了“例外安全”的概念。
通常,您首先需要确定函数需要保证的异常安全级别。等级
基本保证只是意味着面对异常或其他错误,没有资源被泄露,强有力的保证说程序状态回滚到异常之前,并且nothrow方法永远不会抛出异常。
我个人在发生意外的运行时故障时使用异常。意外的意味着我不应该在正常的操作过程中发生这样的故障。运行时意味着错误是由于我控制之外的某些外部组件的状态,而不是由于我的逻辑错误。我使用ASSERT()来捕获逻辑错误,并使用布尔返回值来预期错误。
为什么呢? ASSERT没有编译成发布代码,所以我不会给我的用户带来错误检查我自己的失败。这就是单元测试和ASSERTS的用途。布林因为抛出异常会给出错误的信息。例外情况也很昂贵。如果我在正常的应用程序执行过程中抛出异常,那么我就不能使用MS Visual Studio调试器出色的“Catch on thrown”异常功能,我可以让调试器在 any < any <抛出异常,而不是仅在非处理(崩溃)异常时停止的默认值。
要查看基本保证的C ++技术,谷歌“RAII”(资源获取是初始化)。这是一种将资源包装在一个对象中的技术,该对象的构造函数分配资源,而析构函数则释放资源。由于C ++异常展开堆栈,它可以保证在异常情况下释放资源。您可以使用此技术在异常情况下回滚程序状态。只需向对象添加“Commit”方法,如果对象在销毁之前未提交,请运行“回滚”操作,在析构函数中恢复程序状态。
答案 2 :(得分:2)
应用程序中的每个“模块”都负责处理自己的输入参数。通常情况下,您应该尽快找到问题,而不是将垃圾交给应用程序的其他部分,并依赖它们是正确的。但也有例外。有时验证输入参数基本上需要在调用者中重新实现被调用者应该做的事情(例如,解析整数)。在这种情况下,通常适合尝试操作并查看它是否有效。此外,有些操作无法在不执行操作的情况下预测其成功。例如,在写入文件之前,您无法可靠地检查是否可以写入文件:另一个进程可能会在您检查后立即锁定文件。
答案 3 :(得分:1)
我遇到的异常处理没有真正严格的规则,但我有一些我想要应用的一般经验法则。
即使在系统的较低层处理了一些异常,也要确保在系统的入口点有一个catch all异常处理程序(例如,当你实现一个新的Thread(即Runnable),Servlet,MessasgeDrivenBean,server插座等)。这通常是做出最终决定的最佳位置,因为系统应该如何继续(记录并重试,退出并返回错误,回滚事务)
永远不要在finally块中抛出一个execption,你将失去原始异常并用一个不重要的错误掩盖真正的问题。
除此之外,它取决于您正在实施的功能。您是否处于循环中,是否应重试其余项目或整个列表中止?
如果您重新抛出异常,请避免记录,因为它只会在日志中添加噪音。
答案 4 :(得分:0)
我通常认为,如果作为方法的调用者,我可以以任何方式使用异常(例如,通过采用不同的方法从中恢复),或者如果它没有区别,并且如果发生异常则出错。所以在前一种情况下,我将声明抛出异常的方法,而在后者中我会在方法内部捕获它,并且不会打扰它的调用者。
答案 5 :(得分:0)
关于捕获例外的唯一问题是“有多种策略可以完成某些事情吗?”
某些功能可以有意义地捕获某些异常,并在发生这些已知异常时尝试替代策略。
将抛出所有其他异常。
如果没有任何替代策略,将简单抛出异常。
你很少想要一个捕捉(和沉默)异常的功能。一个例外意味着出了问题。应用程序 - 作为一个整体 - 应该知道未处理的异常。它应该至少记录它们,也许甚至更多:关闭或重启。