我为我的应用程序不期望的每个条件创建了异常。UserNameNotValidException, PasswordNotCorrectException等。
然而,我被告知我不应该为这些条件创造例外。在我的UML中,那些是主要流程的异常,那么为什么它不应该是异常呢?
是否有创建异常的指导或最佳实践?
我为我的应用程序不期望的每个条件创建了异常。UserNameNotValidException, PasswordNotCorrectException等。
然而,我被告知我不应该为这些条件创造例外。在我的UML中,那些是主要流程的异常,那么为什么它不应该是异常呢?
是否有创建异常的指导或最佳实践?
当前回答
异常与返回错误代码参数应该是关于流控制的,而不是哲学(错误有多“异常”):
void f1() throws ExceptionType1, ExceptionType2 {}
void catchFunction() {
try{
while(someCondition){
try{
f1();
}catch(ExceptionType2 e2){
//do something, don't break the loop
}
}
}catch(ExceptionType1 e1){
//break the loop, do something else
}
}
其他回答
一般来说,你想要为应用程序中可能发生的任何异常抛出一个"异常"
在您的示例中,这两个异常看起来都是通过密码/用户名验证调用的。在这种情况下,有人会输入错误的用户名/密码并不是什么例外。
它们是UML主要流程的“例外”,但在处理过程中是更多的“分支”。
如果您试图访问您的passwd文件或数据库,但无法访问,这将是一个异常情况,并需要抛出异常。
在决定异常是否合适时,需要考虑一些有用的事情:
what level of code you want to have run after the exception candidate occurs - that is, how many layers of the call stack should unwind. You generally want to handle an exception as close as possible to where it occurs. For username/password validation, you would normally handle failures in the same block of code, rather than letting an exception bubble up. So an exception is probably not appropriate. (OTOH, after three failed login attempts, control flow may shift elsewhere, and an exception may be appropriate here.) Is this event something you would want to see in an error log? Not every exception is written to an error log, but it's useful to ask whether this entry in an error log would be useful - i.e., you would try to do something about it, or would be the garbage you ignore.
我个人的指导方针是:当发现当前代码块的基本假设为假时抛出异常。
例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的函数,这条线很难画出来,但底线是:如果函数对其输入的假设违反了,它应该抛出异常,而不是正常返回。
这个等式的另一方面是:如果你发现你的函数经常抛出异常,那么你可能需要改进它们的假设。
安全性与您的示例混为一谈:您不应该告诉攻击者用户名存在,但密码是错误的。这是你不需要分享的额外信息。只要说“用户名或密码不正确”。
我的小指南很大程度上受到了“代码完成”这本伟大的书的影响:
使用异常来通知不应该被忽略的事情。 如果错误可以在本地处理,就不要使用异常 确保异常与例程的其余部分处于相同的抽象级别。 异常应该留给真正的异常。