Kon*_*rad 424 c++ java exception-handling exception try-catch
我一直认为,如果一个方法可以抛出一个异常,那么不顾及用一个有意义的try块来保护这个调用.
我刚刚发布了' 你应该总是包装可以抛出try,catch块的调用.'对这个问题,并被告知这是'非常糟糕的建议' - 我想明白为什么.
Mit*_*eat 332
一个方法应该只能在一些合理的方式处理异常时捕获异常.
否则,将其传递给up,希望调用堆栈上方的方法可以理解它.
正如其他人所指出的那样,最好在调用堆栈的最高级别拥有一个未处理的异常处理程序(带有日志记录),以确保记录任何致命错误.
D.S*_*ley 135
正如米奇 和 其他人所说,你不应该抓住一个例外,你不打算以某种方式处理.您应该考虑应用程序在设计时如何系统地处理异常.这通常会导致基于抽象的错误处理层 - 例如,您处理数据访问代码中的所有SQL相关错误,以便与域对象交互的应用程序部分不会暴露于那里的事实某个地方是引擎盖下的DB.
除了"随处可见"之外,还有一些相关的代码气味,你绝对要避免.
"catch,log,rethrow":如果你想要基于范围的日志记录,那么当堆栈因异常(ala std::uncaught_exception()
)展开时,编写一个在其析构函数中发出日志语句的类.您需要做的就是在您感兴趣的范围内声明一个日志记录实例,瞧,您有日志记录,没有不必要的try
/ catch
逻辑.
"catch,throw translated":这通常指向一个抽象问题.除非您正在实现一个联合解决方案,您将几个特定异常转换为一个更通用的异常,否则您可能有一个不必要的抽象层...... 并且不要说"明天我可能需要它".
"抓住,清理,重新抛出":这是我的宠儿之一.如果您看到很多这样的内容,那么您应该应用资源获取是初始化技术,并将清理部分放在janitor对象实例的析构函数中.
我认为充满try
/ catch
blocks的代码是代码审查和重构的良好目标.它表明要么没有很好地理解异常处理,要么代码已成为amœba并且非常需要重构.
sha*_*oth 46
因为下一个问题是"我遇到了异常,我接下来该怎么做?" 你会怎么做?如果你什么都不做 - 这就是隐藏的错误,程序可能"无法正常工作"而没有任何机会找到发生的事情.一旦你发现异常,你需要了解你将会做什么,如果你知道的话,只能抓住.
Ash*_*ain 28
您不需要使用try-catches 覆盖每个块,因为try-catch仍然可以捕获调用堆栈中进一步调用的函数中未处理的异常.因此,不是让每个函数都有一个try-catch,你可以在应用程序的顶层逻辑中使用一个.例如,可能有一个SaveDocument()
顶级例程,它调用许多调用其他方法的方法等.这些子方法不需要自己的try- SaveDocument()
catch ,因为如果它们抛出,它仍然被捕获.
这很好,有三个原因:它很方便,因为你只有一个地方可以报告错误:SaveDocument()
catch块.没有必要在所有子方法中重复这一点,而且无论如何都是你想要的:一个单一的地方可以让用户对出错的东西进行有用的诊断.
第二,每当抛出异常时都会取消保存.随着每个子方法试捕,如果抛出一个异常,你在该方法的catch块,执行离开的功能,它进行通过SaveDocument()
.如果事情已经出错了你可能想要在那里停下来.
三,所有子方法都可以假设每次调用都成功.如果调用失败,执行将跳转到catch块,后续代码永远不会执行.这可以使您的代码更清晰.例如,这里有错误代码:
int ret = SaveFirstSection();
if (ret == FAILED)
{
/* some diagnostic */
return;
}
ret = SaveSecondSection();
if (ret == FAILED)
{
/* some diagnostic */
return;
}
ret = SaveThirdSection();
if (ret == FAILED)
{
/* some diagnostic */
return;
}
Run Code Online (Sandbox Code Playgroud)
以下是使用例外编写的方法:
// these throw if failed, caught in SaveDocument's catch
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();
Run Code Online (Sandbox Code Playgroud)
现在发生的事情要清楚得多.
注意异常安全代码以其他方式编写可能比较困难:如果抛出异常,您不希望泄漏任何内存.确保您了解RAII,STL容器,智能指针以及在析构函数中释放资源的其他对象,因为对象总是在异常之前被破坏.
我听过的最好的建议是你应该只在你可以明智地对异常情况做些什么的时候捕捉异常,并且"捕获,记录和释放"不是一个好的策略(如果在图书馆偶尔不可避免).
我同意你的问题的基本方向,以尽可能多地处理最低级别的例外情况.
一些现有的答案就像"你不需要处理异常.其他人会在堆栈中做到这一点." 根据我的经验,这是一个错误的借口,不考虑当前开发的代码中的异常处理,使异常处理别人或以后的问题.
在分布式开发中,这个问题会急剧增加,您可能需要调用同事实现的方法.然后你必须检查一个嵌套的方法调用链,找出他/她为什么抛出一些异常的原因,这可以在最深的嵌套方法中更容易处理.
我得到了挽救几个项目的“机会”,高管更换了整个开发团队,因为应用程序有太多错误,用户厌倦了这些问题和四处奔波。这些代码库都在应用程序级别进行了集中式错误处理,就像投票最高的答案所描述的那样。如果该答案是最佳实践,为什么它不起作用并允许以前的开发团队解决问题?也许有时它不起作用?上面的答案没有提到开发人员花多长时间解决单个问题。如果解决问题的时间是关键指标,那么使用 try..catch 块检测代码是更好的做法。
我的团队如何在不显着改变 UI 的情况下解决问题?简单,每个方法都使用 try..catch 进行检测,并在失败点使用方法名称记录所有内容,方法参数值连接成一个字符串,连同错误消息、错误消息、应用程序名称、日期、和版本。有了这些信息,开发人员可以对错误进行分析,以确定发生最多的异常!或者错误数量最多的命名空间。它还可以验证模块中发生的错误是否得到了正确处理,并且不是由多种原因引起的。
这样做的另一个好处是开发人员可以在错误记录方法中设置一个断点,并且通过一个断点和单击“step out”调试按钮,他们可以完全访问实际的方法失败故障点的对象,可在即时窗口中方便地使用。它使调试变得非常容易,并允许将执行拖回到方法的开头以复制问题以找到确切的行。集中式异常处理是否允许开发人员在 30 秒内复制异常?不。
声明“一个方法应该只在它可以以某种合理的方式处理异常时才能捕获异常。” 这意味着开发人员可以预测或将遇到可能在发布之前发生的每个错误。如果这是顶级的,那么就不需要应用程序异常处理程序,并且 Elastic Search 和 logstash 将没有市场。
这种方法还可以让开发人员找到并修复生产中的间歇性问题!您想在生产中没有调试器的情况下进行调试吗?或者您更愿意接听电话并收到来自心烦意乱的用户的电子邮件?这使您可以在其他人知道之前解决问题,而无需通过电子邮件、IM 或 Slack 获得支持,因为解决问题所需的一切都在那里。95% 的问题永远不需要重现。
为了正常工作,它需要与可以捕获命名空间/模块、类名、方法、输入和错误消息并存储在数据库中的集中式日志记录相结合,以便可以将其聚合以突出显示哪个方法最失败,以便它可以首先固定。
有时开发人员会选择从 catch 块向堆栈上抛出异常,但这种方法比不抛出的普通代码慢 100 倍。使用日志记录捕获和释放是首选。
对于财富 500 强公司中的大多数用户来说,这项技术用于快速稳定一个每小时都失败的应用程序,该应用程序由 12 个开发人员在 2 年内开发。使用这 3000 个不同的异常在 4 个月内被识别、修复、测试和部署。这意味着平均每 15 分钟修复一次,持续 4 个月。
我同意输入检测代码所需的所有内容并不有趣,我不喜欢看重复的代码,但从长远来看,为每个方法添加 4 行代码是值得的。
我的计算机科学教授曾给我的建议是:"只有在无法使用标准方法处理错误时才使用Try和Catch块."
作为一个例子,他告诉我们,如果一个程序在一个不可能做的事情的地方遇到一些严重的问题:
int f()
{
// Do stuff
if (condition == false)
return -1;
return 0;
}
int condition = f();
if (f != 0)
{
// handle error
}
Run Code Online (Sandbox Code Playgroud)
然后你应该使用try,catch块.虽然您可以使用异常来处理此问题,但通常不建议这样做,因为异常是性能代价高昂的.
归档时间: |
|
查看次数: |
58358 次 |
最近记录: |