Answers:
通常,对于私有方法,您不会抛出异常,因为在编写时,开发人员应该知道他从何处以及从何处调用方法。这样,作为参数传递给私有方法的变量应在方法外部进行检查,即在调用它之前。对于公共方法(无论是否正在编写“ API”),抛出“ InvalidArgumentException”和其他此类异常被认为是一种好习惯。
对于那些您想抛出“ InvalidArgumentException”的情况,值得一提的是Assert
,自版本1.1.2起,Spring API for Java 中就有一个类。至少对我来说,这对减少执行检查的代码很有帮助。
但是,您可以使用“断言”来检查私有方法中的参数。这是他们的真正目的之一。它们是使用它们的更多原因,请查看以下链接,该链接还彻底说明了何时使用断言以及何时使用异常。断言不在生产代码中,编译器默认将其删除。因此,它们就是您想要的:帮助开发人员,对于用户而言是隐形的。在Java中,您必须使用特殊标志(“ -ea”)告诉编译器启用断言。您可以将他们视为“调试”朋友。
这是在以下方面使用断言的方法:
我意识到,尽管这个问题没有语言标签,但它可能是在隐含地谈论“咖啡语言”。但是,仅出于完整性考虑,我想提及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
被#define
D到A编译时间常数,以便编译器可以完全消除在所有的参数检查代码优化构建。(我并不是说编译签出通常是一件好事,但我确实相信用户应该可以选择将其编译出来。)
我仍然喜欢这种解决方案,因为参数检查代码清晰可见,并分组到if
。但是,第二个和第三个问题不能由此解决。因此,我现在再次倾向于使用assert
宏进行参数检查。
该升压编码标准同意这一点:
程序员错误呢?
作为开发人员,如果我违反了所用库的先决条件,则我不希望取消堆栈。我想要的是一个核心转储或等效的转储-一种在检测到问题的确切点检查程序状态的方法。这通常意味着
assert()
或类似的东西。
John Lakos在CppCon'14上做了一个非常有趣的演讲,题目是Defensive Programming Done Right(第1 部分,第2部分)。在演讲的第一部分,他讨论了契约和不确定行为的理论。在第二部分中,他提出了我认为对系统论证检查非常好的建议。从本质上讲,他提出了断言宏,该宏使用户可以选择她愿意捐赠给库中多少预算(就CPU利用率而言)以进行参数检查,并让库明智地使用该预算。此外,用户还可以安装全局错误处理功能,以在检测到合同违约时调用该功能。
关于函数是私有的方面,我不认为这意味着我们永远不应该让它检查其参数。我们可能更相信自己的代码不会违反内部函数的约定,但我们也知道我们也不完美。内部函数中的参数检查与检测客户端代码中的错误的公共函数一样,对于检测我们自己的错误同样有用。
考虑以下结构:
内部逻辑:假定使用正确的参数调用此函数,因此使用断言来验证前置条件,后置条件和不变量以检查内部逻辑。
用户界面包装:该功能包的内部功能,并使用InvalidArgumentExceptions处理错误的价值观,并告诉用户纠正他输入: Assert(x).hasLength(4);
, Assume(y).isAlphanumeric();
,Assert(z).isZipCode();
,Assume(mailAdress).matchesRegex(regex_MailAdress);
,Reject(x).ifEmpty();
,等。
批处理接口包装器:此函数包装内部函数,并使用日志记录,有效性标记和统计信息来处理错误的值,而不会中断某些长时间运行的任务。以后,检查和清理结果数据库的人员可以使用这些标记。
命令行界面包装器:此函数包装内部函数,并再次询问最后输入。
对于不同的任务,您应该同时使用-断言和异常-不同的方法。您应该将内部逻辑与参数检查分开。将其与模型,视图,控制器的分离进行比较。