您是否从私有方法中抛出argumentsexception或argumentsnullexception?


20

我刚刚回顾了一段时间后写的一些代码,可以看到我有几个私有方法,如果方法参数存在问题,它们会抛出argumentsnullexceptions和/或argumentsexceptions。

我想我的理由是,如果将来有人尝试“滥用”该方法,则可以帮助将来证明该应用程序。但是,由于这是一个私有方法,可能调用此方法的人员可以看到相关的注释和代码,因此不必抛出此代码。拥有它们当然不会有任何伤害,尽管确实会增加混乱。

我的感觉是,这些异常通常在将公开公开的API之类的东西上更有用。

Answers:


22

通常,对于私有方法,您不会抛出异常,因为在编写时,开发人员应该知道他从何处以及从何处调用方法。这样,作为参数传递给私有方法的变量应在方法外部进行检查,即在调用它之前。对于公共方法(无论是否正在编写“ API”),抛出“ InvalidArgumentException”和其他此类异常被认为是一种好习惯。

对于那些您想抛出“ InvalidArgumentException”的情况,值得一提的是Assert,自版本1.1.2起,Spring API for Java 中就有一个类。至少对我来说,这对减少执行检查的代码很有帮助。

但是,您可以使用“断言”来检查私有方法中的参数。这是他们的真正目的之一。它们是使用它们的更多原因,请查看以下链接,该链接还彻底说明了何时使用断言以及何时使用异常。断言不在生产代码中,编译器默认将其删除。因此,它们就是您想要的:帮助开发人员,对于用户而言是隐形的。在Java中,您必须使用特殊标志(“ -ea”)告诉编译器启用断言。您可以将他们视为“调试”朋友。

这是在以下方面使用断言的方法:


1
Apache Commons还具有一个Validate类,其功能类似于Spring的Assert类
Rosa Richter

@cantido是的,我还要补充一点,Google的Guava中的Preconditions类的工作方式相同。感谢您提供信息:-)
Jalayn

2

像其他一切一样,这取决于...。

如果公共方法是调用私有方法的简单包装器(沿着私有重载方法的行),则在私有方法中引发异常而不是检入每个公共方法是有意义的。

通常,如果它不满足上述定义,那么我通常不会检查参数/在私有方法上引发异常。尽管在其他情况下,我通常会在执行一些昂贵的操作之前使用私有方法执行此操作,如果参数无效,这些操作可能会部分失败。


2

我意识到,尽管这个问题没有语言标签,但它可能是在隐含地谈论“咖啡语言”。但是,仅出于完整性考虑,我想提及C ++世界中一些明显不同的共识。

C ++程序员通常会对三件事感兴趣:

  • 在优化的版本中,其开销是否为零?(也就是说,可以“编译出来”吗?)
  • 我可以在检测到错误时使用它来捕获调试器吗?
  • 我可以用它来报告声明的函数中的问题noexcept吗?

过去,我通过编写这样的代码来解决第一个问题

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

其中CHECK_ARGS#defineD到A编译时间常数,以便编译器可以完全消除在所有的参数检查代码优化构建。(我并不是说编译签出通常是一件好事,但我确实相信用户应该可以选择将其编译出来。)

我仍然喜欢这种解决方案,因为参数检查代码清晰可见,并分组到if。但是,第二个和第三个问题不能由此解决。因此,我现在再次倾向于使用assert宏进行参数检查。

升压编码标准同意这一点:

程序员错误呢?

作为开发人员,如果我违反了所用库的先决条件,则我不希望取消堆栈。我想要的是一个核心转储或等效的转储-一种在检测到问题的确切点检查程序状态的方法。这通常意味着assert()或类似的东西。

John LakosCppCon'14上了一个非常有趣的演讲,题目是Defensive Programming Done Right第1 部分第2部分)。在演讲的第一部分,他讨论了契约和不确定行为的理论。在第二部分中,他提出了我认为对系统论证检查非常好的建议。从本质上讲,他提出了断言宏,该宏使用户可以选择她愿意捐赠给库中多少预算(就CPU利用率而言)以进行参数检查,并让库明智地使用该预算。此外,用户还可以安装全局错误处理功能,以在检测到合同违约时调用该功能。

关于函数是私有的方面,我不认为这意味着我们永远不应该让它检查其参数。我们可能更相信自己的代码不会违反内部函数的约定,但我们也知道我们也不完美。内部函数中的参数检查与检测客户端代码中的错误的公共函数一样,对于检测我们自己的错误同样有用。


1

考虑以下结构:

  1. 内部逻辑:假定使用正确的参数调用此函数,因此使用断言来验证前置条件,后置条件和不变量以检查内部逻辑。

  2. 用户界面包装:该功能包的内部功能,并使用InvalidArgumentExceptions处理错误的价值观,并告诉用户纠正他输入: Assert(x).hasLength(4);Assume(y).isAlphanumeric();Assert(z).isZipCode();Assume(mailAdress).matchesRegex(regex_MailAdress);Reject(x).ifEmpty();,等。

  3. 批处理接口包装器:此函数包装内部函数,并使用日志记录,有效性标记和统计信息来处理错误的值,而不会中断某些长时间运行的任务。以后,检查和清理结果数据库的人员可以使用这些标记。

  4. 命令行界面包装器:此函数包装内部函数,并再次询问最后输入。

对于不同的任务,您应该同时使用-断言和异常-不同的方法。您应该将内部逻辑与参数检查分开。将其与模型,视图,控制器的分离进行比较。


0

有避免空引用检查的更好方法:使用代码协定或AOP框架为您执行检查。Google“ c#代码合同”或“ postsharp”。


我想我的问题也将扩展到代码合同。是否需要在私有方法中检查方法的前提条件(例如,以供将来校对,或阻止您用脚射击)?
穆斯先生
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.