validation数据时抛出exception是好的还是坏的想法?
在validation数据的时候,我养成了以下的习惯
*注:我没有真正有每个检查个人布尔值。 这仅仅是例子。
*另一个注意:在testing过程中的任何error handling都正确完成。 在try-catch中引发的唯一例外是我自己的。
Try { if(validCheckOne = false) { throw new Exception("Check one is bad"); } if(validCheckTwo = false) { throw new Exception("Fail'D because of check2"); } if(validCheckTen = false) { throw new Exception("Yet another failure on your part: check10."); } } catch(Exception e) { MessageBox.Show("Your stupid data is wrong! See for yourself: " + e.Message); }
这是不好的做法? 抛出exception是否会减慢程序的执行速度,或者是不可取的?
就我个人而言,我喜欢为业务规则validation抛出exception(而不是用户inputvalidation),因为它迫使问题被上游处理。 如果我的业务对象返回了某种validation结果,则调用者可能会忽略它。 如果你愿意,叫我牛仔:)
这里的每个人都在重复“例外是为了特殊情况”这个短语,但是这实际上并没有理解为什么它不适合在普通情况下使用它们。 我需要的不仅仅是这些。 抛出exception的性能打击真的很糟糕吗? 有没有可用的基准?
我要重复这里的口头禅:抛出exception应该在特殊情况下进行。 input的数据无效确实不是那么特殊。
我支持MusiGenesis的答案。
另外…
抛出exception的性能是一千个指令。 这与最终用户的时间相比没有什么意义,但是在内部代码中是很慢的。
另一个问题是,使用例外, 你的validation仅限于报告第一次失败 (下一次你将不得不再次做下一次失败)。
除了经常重复的声明,“例外情况是特殊情况下”,这是一个额外的澄清规则,我已经喜欢:
如果用户造成了这种情况,那也不例外。
例外情况是系统方面的事情(服务器正在closures,资源不可用),而不是用户做奇怪的事情,因为所有的用户都做了奇怪的事情。
在标题中你称之为“validation”数据。 这可能发生在几个层面上。 在您正在检查用户input数据的GUI中(附近),您应该期待错误,并有方法将错误报告回来。 在这种情况下,例外情况是不合适的
但是数据validation也可能发生在其他边界,比如说商业规则类之间。 在那里,数据中的错误是罕见的和意外的。 你应该扔掉,当你发现一个。
这取决于 – 如果你期望数据在那里,而不是有数据意外,然后抛出一个exception是好的。 抛出exception非常昂贵(缓慢),但是处理意外情况的最佳方式。
所以也许在某些语言中exception抛出和捕获是“昂贵的”,但在其他语言中,抛出和捕获exception正是所谓的。
例如,在Smalltalk中,可以快速构build一个多层次的exception捕获解决scheme。 validation过程可以收集任何数量的exception,代表一切,特定的input数据集是错误的。 然后,它会把他们全部交给一个更高级别的捕手,负责形成一个人类可读的解释,再一次,这个input是错误的。 反过来,它会把这个链条进一步抛出一个例外,连同格式化的解释。
所以…我想我说的是,如果你没有任何exception处理架构支持捕捉它们并且用它们做合理的事情,那么exception抛出是不好的,所有捕捉器要做的就是退出或者做别的东西同样不合适。
一般来说,使用exception来实现条件stream是不可取的。 做这样的事情会更好
error = false; while(true) { if(validCheckOne == false) { msg = "Check one is bad"; error = true; break; } if(validCheckTwo == false) { msg = "Check two is bad"; error = true; break; } ... break; } if (error) { .. }
在出现这种情况时,你应该抛出一个exception。 更高层次的软件将有机会捕捉exception并做一些事情 – 即使这只是简单地使应用程序崩溃。
这是不好的行为。 例外情况是特殊情况。 他们需要资源来生成堆栈等。不应该使用exception来规定stream程。
我一般同意“例外应该是例外”的规则,但是我可能会为Python做一个例外(ha!),在这种情况下,使用try …除了控制stream程之外,它可以是高效的并且被认为是很好的实践。
例如 ,请参阅使用其他用途的例外 。
我build议使用问题中描述的exception(对于函数内的stream程控制)是错误的,通常不是最好的想法。 我会更进一步说,validation抛出exception不是最好的方法; 而是返回一个布尔值并存储可以访问的validation错误消息列表。 如果在一个无效的对象上调用一个伴随的保存方法,它可能/应该抛出一个exception。
因此,如果validation失败,validation错误消息可以显示给用户(logging,返回任何)。 如果validation通过,那么你可以调用保存。 如果你打电话保存一个无效的对象,那么得到一个适当的例外。
你的示例代码的另一个潜在的问题(取决于当然的要求)是它只会抛出第一个validation错误发生。 想象一下,从用户POV:
- 点击保存
- 获取错误信息
- 正确的错误
- 再次点击保存
- 获取不同的错误消息。 烦人。
作为一个用户,我希望一次返回所有validation错误,所以我可以在再次尝试之前纠正这些错误。
如果你的数据validation是在一个紧密的循环中,那真的很重要。 对于大多数情况,只要您的代码一致 ,就不要紧。
如果你有很多代码看起来像你上面的示例,那么你可能想要通过引入一个帮助器方法来清除它…
private void throwIf( bool condition, String message ) { if( condition ) throw new ApplicationException( message ); }
(同样,这样做将有助于解决诸如“validCheckOne = false”与“validCheckOne == false”之类的错误:)