我为我的应用程序不期望的每个条件创建了异常。UserNameNotValidException, PasswordNotCorrectException等。
然而,我被告知我不应该为这些条件创造例外。在我的UML中,那些是主要流程的异常,那么为什么它不应该是异常呢?
是否有创建异常的指导或最佳实践?
我为我的应用程序不期望的每个条件创建了异常。UserNameNotValidException, PasswordNotCorrectException等。
然而,我被告知我不应该为这些条件创造例外。在我的UML中,那些是主要流程的异常,那么为什么它不应该是异常呢?
是否有创建异常的指导或最佳实践?
当前回答
To my mind, the fundamental question should be whether one would expect that the caller would want to continue normal program flow if a condition occurs. If you don't know, either have separate doSomething and trySomething methods, where the former returns an error and the latter does not, or have a routine that accepts a parameter to indicate whether an exception should be thrown if it fails). Consider a class to send commands to a remote system and report responses. Certain commands (e.g. restart) will cause the remote system to send a response but then be non-responsive for a certain length of time. It is thus useful to be able to send a "ping" command and find out whether the remote system responds in a reasonable length of time without having to throw an exception if it doesn't (the caller would probably expect that the first few "ping" attempts would fail, but one would eventually work). On the other hand, if one has a sequence of commands like:
exchange_command("open tempfile"); exchange_command("write tempfile data {whatever}"); exchange_command("write tempfile data {whatever}"); exchange_command("write tempfile data {whatever}"); exchange_command("write tempfile data {whatever}"); exchange_command("close tempfile"); exchange_command("copy tempfile to realfile");
人们会希望任何操作的失败都能中止整个序列。虽然可以检查每个操作以确保操作成功,但如果命令失败,让exchange_command()例程抛出异常会更有帮助。
实际上,在上面的场景中,有一个参数来选择一些失败处理模式可能会有所帮助:从不抛出异常,仅为通信错误抛出异常,或者在命令没有返回“成功”指示的任何情况下抛出异常。
其他回答
一个经验法则是在您通常无法预测的情况下使用异常。例如数据库连接、磁盘上丢失的文件等。对于您可以预测的场景,例如用户试图使用错误的密码登录,您应该使用返回布尔值的函数,并知道如何优雅地处理这种情况。您不希望仅仅因为有人输入了密码错误而抛出异常,从而突然结束执行。
我的小指南很大程度上受到了“代码完成”这本伟大的书的影响:
使用异常来通知不应该被忽略的事情。 如果错误可以在本地处理,就不要使用异常 确保异常与例程的其余部分处于相同的抽象级别。 异常应该留给真正的异常。
You may use a little bit generic exceptions for that conditions. For e.g. ArgumentException is meant to be used when anything goes wrong with the parameters to a method (with the exception of ArgumentNullException). Generally you would not need exceptions like LessThanZeroException, NotPrimeNumberException etc. Think of the user of your method. The number of the conditions that she will want to handle specifically is equal to the number of the type of the exceptions that your method needs to throw. This way, you can determine how detailed exceptions you will have.
顺便说一下,总是尝试为库的用户提供一些避免异常的方法。TryParse就是一个很好的例子,它的存在使你不必使用int。解析并捕获异常。在您的情况下,您可能希望提供一些方法来检查用户名是否有效或密码是否正确,这样您的用户(或您)就不必进行大量异常处理。这将有望产生更易于阅读的代码和更好的性能。
抛出异常会导致堆栈unwind,这对性能有一定影响(承认,现代托管环境在这方面有所改进)。仍然在嵌套的情况下反复抛出和捕获异常是一个坏主意。
可能比这更重要的是,例外是针对特殊情况的。它们不应该用于普通的控制流,因为这会损害代码的可读性。
异常用于异常行为、错误、失败等事件。功能行为、用户错误等应该由程序逻辑来处理。由于错误的帐户或密码是登录例程中逻辑流的一部分,因此它应该能够毫无例外地处理这些情况。