首页 文章

在验证数据时抛出异常是好还是坏?

提问于
浏览
53

在验证数据时,我养成了做以下事情的习惯

*注意:我每次检查都没有真正的布尔值 . 这只是一个例子 .

*另一个注意事项:测试期间的任何错误处理都已正确完成 . 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);
}

这是不好的做法吗?抛出异常会减慢程序的执行速度还是不可取的?

12 回答

  • 1

    只有您的数据验证处于紧密循环中才真正重要 . 对于大多数情况,只要您在代码中保持一致,那么您选择的内容并不重要 .

    如果你有很多代码看起来像你上面的样本那么你可能想要通过引入一个帮助方法来清理它...

    private void throwIf( bool condition, String message )
    {
        if( condition )
            throw new ApplicationException( message );
    }
    

    (另外,这样做有助于解决诸如“validCheckOne = false”与“validCheckOne == false”之类的错误:)

  • 2

    就个人而言,我喜欢为业务规则验证抛出异常(而不是用户输入验证),因为它会强制在上游处理问题 . 如果我的业务对象返回了某种验证结果,则调用者可以忽略它 . 如果你愿意,叫我牛仔:)

    这里的每个人都在重复“例外情况适用于特殊情况”这一短语,但实际上并没有理解为什么在特殊情况下使用它们是不好的 . 我需要更多 . 抛出异常的性能是否真的那么糟糕?有没有可用的基准?

  • 1

    我将在这里重复咒语:应该在特殊情况下抛出异常 . 无效的输入数据确实不是那么特别 .

  • 28

    我支持MusiGenesis的回答 .

    另外...


    抛出异常的 performance 是一千条指令 . 与最终用户时间相比,它没什么,但在内部代码中它很慢 .

    另一个问题是,使用例外, your validation is limited to reporting the first failure (下次你必须再次完成所有操作才能找到下一个失败) .

  • 18

    除了经常重复的声明“例外是针对特殊情况”之外,这里还有一个额外的澄清规则:

    如果用户造成了它,那也不例外 .

    例外情况是系统方面的事情(服务器停机,资源不可用),而不是用户做奇怪的事情,因为所有用户都做奇怪的事情 .

  • 5

    在 Headers 中,您将其称为“验证”数据 . 这可能发生在几个层面上 . 在您检查用户输入数据的GUI中(接近),您应该期待错误并有办法报告错误 . 在这种情况下,例外是不恰当的 .

    但是数据验证也可以发生在其他边界,比如业务规则类之间 . 在那里,数据中的错误是不常见和意外的 . 当你发现一个时,你应该扔掉 .

  • 3

    这取决于 - 如果您希望数据存在并且没有数据是意外的,那么抛出异常就可以了 . 抛出异常非常昂贵(缓慢)但是处理意外情况的最佳方法 .

  • 0

    因此,在某些语言中,异常抛出和捕获可能是“代价高昂”,但在其他语言中,抛出和捕获异常正是所谓的 .

    例如,在Smalltalk中,可以快速构建一个多层异常捕获解决方案 . 验证过程可以收集任意数量的异常,表示特定输入数据集的所有错误 . 然后它会把它们全部扔给更高级别的捕手,负责格式化一个人类可读的解释,再次说明输入错误的一切 . 反过来,它会在链上进一步抛出一个异常,以及格式化的解释 .

    所以...我想我所说的是,如果你没有异常处理架构支持捕获它们并对它们做合理的事情,那么异常只会丢失,而你所有捕获器将要做的就是退出或做别的东西同样不合适 .

  • 10

    这是不好的行为 . 特殊情况适用于特殊情况 . 它们需要资源来生成堆栈等 . 不应使用异常来指示流程 .

  • 2

    通常,不建议使用Exceptions来实现条件流 . 做这样的事情会更好

    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) {
         ..
      }
    

    如果出现无法解决问题的情况,您应该抛出异常 . 更高层次的软件将有机会捕获异常并对其做一些事情 - 即使这只是使应用程序崩溃 .

  • 7

    我通常同意“例外应该是例外”的规则,但我可能会为Python做出例外(ha!),它可以既有效又被认为是使用try的好方法......除了控制流程 .

    例如,请参阅Using Exceptions For Other Purposes .

  • 52

    我建议使用如下所述的例外问题(对于函数内的流控制)是错误的,通常不是最好的主意 . 我会更进一步说,验证抛出异常不是最好的方法;而是返回一个布尔值并存储可以访问的验证错误消息列表 . 如果在无效对象上调用它,则附带的save方法可能/应该抛出异常 .

    因此,如果验证失败,则可以向用户显示验证错误消息(记录,返回等等) . 如果验证通过,则可以调用save . 如果在无效对象上调用save,则获取适当的异常 .

    您的示例代码的另一个潜在问题(当然,取决于要求)是它只会抛出发生的第一个验证错误 . 从用户POV想象一下:

    • 单击“保存”

    • 收到错误讯息

    • 更正错误

    • 再次单击“保存”

    • 获取其他错误消息 . 烦人 .

    作为用户,我希望立即返回所有验证错误,以便我可以在再次尝试之前纠正它们 .

相关问题