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

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

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


当前回答

我个人的指导方针是:当发现当前代码块的基本假设为假时抛出异常。

例1:假设我有一个函数,它应该检查任意类,如果该类继承自List<>,则返回true。这个函数问一个问题:“这个对象是List的后代吗?”这个函数永远不会抛出异常,因为它的操作中没有灰色地带——每个单独的类要么继承了List<>,要么继承了List<>,所以答案总是“是”或“否”。

Example 2: say I have another function which examines a List<> and returns true if its length is more than 50, and false if the length is less. This function asks the question, "Does this list have more than 50 items?" But this question makes an assumption - it assumes that the object it is given is a list. If I hand it a NULL, then that assumption is false. In that case, if the function returns either true or false, then it is breaking its own rules. The function cannot return anything and claim that it answered the question correctly. So it doesn't return - it throws an exception.

这与“负载问题”逻辑谬误相当。每个函数都问一个问题。如果给出的输入使该问题成为谬误,则抛出异常。对于返回void的函数,这条线很难画出来,但底线是:如果函数对其输入的假设违反了,它应该抛出异常,而不是正常返回。

这个等式的另一方面是:如果你发现你的函数经常抛出异常,那么你可能需要改进它们的假设。

其他回答

因为它们是正常发生的事情。异常不是控制流机制。用户经常会输入错误的密码,这不是特例。异常应该是一个真正罕见的事情,UserHasDiedAtKeyboard类型的情况。

一个经验法则是在您通常无法预测的情况下使用异常。例如数据库连接、磁盘上丢失的文件等。对于您可以预测的场景,例如用户试图使用错误的密码登录,您应该使用返回布尔值的函数,并知道如何优雅地处理这种情况。您不希望仅仅因为有人输入了密码错误而抛出异常,从而突然结束执行。

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

我想说,对于什么时候使用异常并没有硬性规定。然而,使用或不使用它们有很好的理由:

使用异常的原因:

The code flow for the common case is clearer Can return complex error information as an object (although this can also be achieved using error "out" parameter passed by reference) Languages generally provide some facility for managing tidy cleanup in the event of the exception (try/finally in Java, using in C#, RAII in C++) In the event no exception is thrown, execution can sometimes be faster than checking return codes In Java, checked exceptions must be declared or caught (although this can be a reason against)

不使用异常的原因:

Sometimes it's overkill if the error handling is simple If exceptions are not documented or declared, they may be uncaught by calling code, which may be worse than if the the calling code just ignored a return code (application exit vs silent failure - which is worse may depend on the scenario) In C++, code that uses exceptions must be exception safe (even if you don't throw or catch them, but call a throwing function indirectly) In C++, it is hard to tell when a function might throw, therefore you must be paranoid about exception safety if you use them Throwing and catching exceptions is generally significantly more expensive compared to checking a return flag

一般来说,我更倾向于在Java中使用异常,而不是在c++或c#中,因为我认为异常,无论是否声明,都是函数正式接口的基本组成部分,因为更改异常保证可能会破坏调用代码。在Java IMO中使用它们的最大优势是,您知道调用者必须处理异常,这提高了正确行为的机会。

正因为如此,在任何语言中,我总是从一个公共类派生一层代码或API中的所有异常,这样调用的代码就总能保证捕获所有异常。另外,我认为在编写API或库时抛出特定于实现的异常类是不好的(即从较低的层包装异常,以便调用者接收到的异常在您的接口上下文中是可以理解的)。

注意,Java区分了一般异常和运行时异常,因为后者不需要声明。我只会使用运行时异常类,当您知道错误是由程序中的错误导致的。

我有三种情况。

Bad or missing input should not be an exception. Use both client side js and server side regex to detect, set attributes and forward back to the same page with messages. The AppException. This is usually an exception that you detect and throw with in your code. In other words these are ones you expect (the file does not exist). Log it, set the message, and forward back to the general error page. This page usually has a bit of info about what happened. The unexpected Exception. These are the ones you don't know about. Log it with details and forward them to a general error page.

希望这能有所帮助