我为我的应用程序不期望的每个条件创建了异常。UserNameNotValidException, PasswordNotCorrectException等。

然而,我被告知我不应该为这些条件创造例外。在我的UML中,那些是主要流程的异常,那么为什么它不应该是异常呢?

是否有创建异常的指导或最佳实践?


当前回答

首先,如果API的用户对特定的、细粒度的故障不感兴趣,那么为他们设置特定的异常就没有任何价值。

由于通常不可能知道什么可能对用户有用,一个更好的方法是有特定的异常,但确保它们继承自一个公共类(例如,std::exception或其在c++中的派生类)。这允许您的客户端捕获特定的异常(如果他们愿意的话),或者捕获更一般的异常(如果他们不关心的话)。

其他回答

抛出异常会导致堆栈unwind,这对性能有一定影响(承认,现代托管环境在这方面有所改进)。仍然在嵌套的情况下反复抛出和捕获异常是一个坏主意。

可能比这更重要的是,例外是针对特殊情况的。它们不应该用于普通的控制流,因为这会损害代码的可读性。

其他人建议不应该使用异常,因为在正常流程中,如果用户输入错误,就会出现错误的登录。我不同意,我不明白其中的道理。与打开文件相比。如果该文件不存在或由于某种原因不可用,则框架将抛出异常。使用上述逻辑是微软的一个错误。他们应该返回一个错误代码。解析、webrequest等也一样。

I don't consider a bad login part of a normal flow, it's exceptional. Normally the user types the correct password, and the file does exist. The exceptional cases are exceptional and it's perfectly fine to use exceptions for those. Complicating your code by propagating return values through n levels up the stack is a waste of energy and will result in messy code. Do the simplest thing that could possibly work. Don't prematurely optimize by using error codes, exceptional stuff by definition rarely happens, and exceptions don't cost anything unless you throw them.

一般来说,你想要为应用程序中可能发生的任何异常抛出一个"异常"

在您的示例中,这两个异常看起来都是通过密码/用户名验证调用的。在这种情况下,有人会输入错误的用户名/密码并不是什么例外。

它们是UML主要流程的“例外”,但在处理过程中是更多的“分支”。

如果您试图访问您的passwd文件或数据库,但无法访问,这将是一个异常情况,并需要抛出异常。

我想说,基本上每一个原教旨主义都会导致地狱。

您当然不希望以异常驱动流结束,但是完全避免异常也是一个坏主意。你必须在两种方法之间找到平衡。我不会为每种异常情况创建异常类型。这是没有成效的。

我通常更喜欢创建两种基本类型的异常,它们在整个系统中使用:LogicalException和TechnicalException。如果需要,可以通过子类型进一步区分这些类型,但通常不是没有必要。

技术异常指的是真正意想不到的异常,比如数据库服务器宕机,到web服务的连接抛出IOException等等。

另一方面,逻辑异常用于将不太严重的错误情况传播到上层(通常是一些验证结果)。

请注意,即使是逻辑异常也不是为了定期使用来控制程序流,而是为了突出显示流何时应该真正结束的情况。在Java中使用时,这两种异常类型都是RuntimeException子类,错误处理是高度面向方面的。

因此,在登录示例中,创建类似AuthenticationException的东西并通过枚举值(如UsernameNotExisting、PasswordMismatch等)来区分具体情况可能是明智的。这样就不会产生巨大的异常层次结构,并且可以将捕获块保持在可维护的级别。您还可以轻松地使用一些通用的异常处理机制,因为您已经对异常进行了分类,并且非常清楚要向用户传播什么以及如何传播。

我们的典型用法是,当用户输入无效时,在Web服务调用期间抛出LogicalException。异常被编组到SOAPFault详细信息,然后在客户机上再次被解组到异常,这将导致在某个web页面输入字段上显示验证错误,因为异常已正确映射到该字段。

这当然不是唯一的情况:您不需要点击web服务来抛出异常。你可以在任何特殊情况下自由地这样做(比如在你需要快速失败的情况下)——这都取决于你的判断。

异常类就像“正常”类。当一个新类“是”一个不同类型的对象,具有不同的字段和不同的操作时,您可以创建一个新类。

As a rule of thumb, you should try balance between the number of exceptions and the granularity of the exceptions. If your method throws more than 4-5 different exceptions, you can probably merge some of them into more "general" exceptions, (e.g. in your case "AuthenticationFailedException"), and using the exception message to detail what went wrong. Unless your code handles each of them differently, you needn't creates many exception classes. And if it does, may you should just return an enum with the error that occured. It's a bit cleaner this way.