3 回答
TA贡献1808条经验 获得超4个赞
对我来说,想要捕获异常并将它们转换为错误代码似乎很奇怪。为什么在后者是Java和C#中的默认值时,您认为调用者更喜欢错误代码而不是异常?
至于你的问题:
您应该只捕获实际可以处理的异常。在大多数情况下,捕获异常并不是正确的做法。有一些例外(例如,线程之间的日志记录和编组异常),但即使对于这些情况,通常也应该重新抛出异常。
你的代码中绝对不应该有很多try / catch语句。同样,我们的想法是只捕获您可以处理的异常。您可以包含一个最顶层的异常处理程序,将任何未处理的异常转换为对最终用户有用的东西,但是否则您不应该尝试捕获每个可能位置的每个异常。
TA贡献1836条经验 获得超4个赞
这取决于应用和情况。如果你构建一个库组件,你应该冒出异常,尽管它们应该被包装成与你的组件一起上下文。例如,如果您构建一个Xml数据库并假设您正在使用文件系统来存储数据,并且您正在使用文件系统权限来保护数据。您不希望冒出一个FileIOAccessDenied异常,因为它会泄漏您的实现。相反,您将包装异常并抛出AccessDenied错误。如果您将组件分发给第三方,则尤其如此。
至于是否可以吞下例外。这取决于你的系统。如果您的应用程序可以处理故障情况,并且通知用户失败的原因没有任何好处,那么请继续,尽管我强烈建议您记录失败。我总是觉得很难打电话来帮助解决问题并发现他们正在吞下异常(或者替换它并抛出新的异常而不设置内部异常)。
一般来说,我使用以下规则:
在我的组件和库中,如果我打算处理它或基于它做某些事情,我只会捕获异常。或者,如果我想在异常中提供其他上下文信息。
我在应用程序入口点或尽可能高的级别使用常规try catch。如果异常到达此处,我只需记录它并让它失败。理想情况下,异常永远不会到达此处
我发现以下代码是一种气味:
try{ //do something}catch(Exception){ throw;}
像这样的代码没有任何意义,不应该包括在内。
TA贡献1784条经验 获得超8个赞
我想就这个主题推荐另一个好的来源。这是对C#和Java,Anders Hejlsberg和James Gosling的发明者的访谈,分别是关于Java的Checked Exception的主题。
页面底部还有很多资源。
我倾向于同意Anders Hejlsberg和你的看法,大多数来电者只关心操作是否成功。
Bill Venners:您提到了关于已检查异常的可扩展性和版本控制问题。你能澄清这两个问题的含义吗?
Anders Hejlsberg:让我们从版本开始,因为问题很容易在那里看到。假设我创建了一个声明它抛出异常A,B和C的方法foo。在foo的第二个版本中,我想添加一些功能,现在foo可能会抛出异常D.这对我来说是一个彻底的改变。将D添加到该方法的throws子句中,因为该方法的现有调用者几乎肯定不会处理该异常。
在新版本中向throws子句添加新异常会破坏客户端代码。这就像在界面中添加方法一样。在发布接口之后,它实际上是不可变的,因为它的任何实现都可能具有您要在下一个版本中添加的方法。所以你必须创建一个新的界面。与异常类似,您可能必须创建一个名为foo2的全新方法,该方法会抛出更多异常,或者您必须在新foo中捕获异常D,并将D转换为A,B或C.
Bill Venners:但是你不是在这种情况下破坏他们的代码,即使是在没有检查异常的语言中吗?如果foo的新版本将抛出一个客户应该考虑处理的新异常,那么他们的代码是不是因为他们在编写代码时没有预料到异常这一事实?
Anders Hejlsberg:不,因为在很多情况下,人们并不关心。他们不会处理任何这些例外情况。它们的消息循环周围有一个底层异常处理程序。那个处理程序只是打开一个对话框,说明出了什么问题并继续。程序员通过在任何地方编写try finally来保护他们的代码,因此如果发生异常他们将正确退出,但他们实际上并不感兴趣处理异常。
throws子句,至少它在Java中的实现方式,并不一定会强制您处理异常,但如果您不处理它们,它会强制您确切地确认哪些异常可能会通过。它要求您捕获声明的异常或将它们放在您自己的throws子句中。为了解决这个问题,人们做了荒谬的事情。例如,他们用“抛出异常”来装饰每个方法。这完全打败了这个功能,你只是让程序员写了更多的gobbledy gunk。这对任何人都没有帮助。
编辑:添加了有关转换的更多详细信息
添加回答
举报