我来自.NET背景,现在正在使用Java。
目前,我在设计防御输入错误的API方面存在很大问题。假设我有以下代码(足够接近):
public void setTokens(Node node, int newTokens) {
tokens.put(node, newTokens);
}
但是,此代码可能由于两个原因而失败:
null
节点。在.NET中,我会分别抛出ArgumentNullException
(而不是NullReferenceException
!)或ArgumentException
,传递有问题的参数的名称(node
)作为string
参数。
Java似乎没有等效的例外。我意识到我可以更具体,只是抛出最接近描述情况的异常,或者甚至为特定情况编写我自己的异常类。
这是最佳做法吗?或者是否存在类似于.NET中的ArgumentException
的通用类?
在这种情况下检查 null
是否有意义?无论如何代码都会失败,异常的堆栈跟踪将包含上面的方法调用。检查null
似乎是多余和过分的。当然,堆栈跟踪将略微更清洁(因为它的目标是上述方法,而不是JRE的HashMap
实现中的内部检查)。但这必须抵消额外的if
语句的成本,此外,永远不会发生 - 毕竟,将null
传递给上述方法不是预期的情况,这是一个相当愚蠢的错误。期待它是彻头彻尾的偏执 - 即使我没有检查它也会失败,同样的例外。
[正如评论中指出的那样,HashMap.put
实际上允许密钥的null
值。因此,对null
的检查在这里不一定是多余的。]
答案 0 :(得分:12)
标准Java异常是IllegalArgumentException
。如果参数为null,有些人会抛出NullPointerException
,但对我来说NPE有“有人搞砸”的含义,而且你不希望你的API的客户认为你不知道你在做什么。
对于公共API,检查参数并尽早和干净地失败。时间/成本几乎不重要。
答案 1 :(得分:7)
在Java中,您通常会抛出IllegalArgumentException
答案 2 :(得分:7)
不同的群体有不同的标准。
首先,我假设您知道RuntimeException
s(未选中)和普通Exception
(已选中)之间的区别,如果没有,请参阅this question and the answers。如果您编写自己的异常,则可以强制它被捕获,而NullPointerException
和IllegalArgumentException
都是RuntimeExceptions,在某些圈子中不赞成。
其次,与您一样,我曾与之合作但不主动使用断言的群组,但如果您的团队(或API的使用者)已决定使用断言,则断言声音就像正确的机制一样。
如果我是你,我会使用NullPointerException
。其原因是先例。从Sun获取示例Java API,例如java.util.TreeSet。这使用NPE来处理这种情况,虽然它看起来像你的代码只是使用了null,但这是完全合适的。
正如其他人所说IllegalArgumentException
是一个选项,但我认为NullPointerException更具沟通性。
如果此API旨在供外部公司/团队使用,我会坚持使用NullPointerException
,但请确保它在javadoc中声明。如果它是供内部使用的话,你可能会认为添加自己的Exception heirarchy是值得的,但我个人觉得那些添加了大量异常heirarchies的API只会被printStackTrace()
d或者记录下来,这只是浪费努力。
在一天结束时,主要的是您的代码清晰地沟通。本地例外的heirarchy就像当地的行话一样 - 它为内部人员添加了信息,但可能会让局外人感到困惑。
关于对null的检查,我认为它确实有意义。首先,它允许您在构造有用的异常时添加有关null(即节点或标记)的消息。其次,将来您可能会使用允许Map
的{{1}}实现,然后您将丢失错误检查。成本几乎为零,所以除非探查者说这是一个内循环问题,否则我不担心。
答案 3 :(得分:2)
您的方法完全取决于您的函数为调用者提供的契约 - 它是节点不为空的前提条件吗?
如果是,那么如果node为null,则应抛出异常,因为它是合同违规。如果不是,那么你的函数应该静默处理空节点并做出适当的响应。
答案 4 :(得分:2)
如果您需要有关如何编写优秀Java代码的指南,我强烈推荐Joshua Bloch撰写的Effective Java一书。
答案 5 :(得分:2)
听起来这可能适用于assert:
public void setTokens(Node node, int newTokens) {
assert node != null;
tokens.put(node, newTokens);
}
答案 6 :(得分:1)
我认为很大程度上取决于方法的合同以及调用者的熟悉程度。
在此过程中的某个时刻,调用者可以在调用您的方法之前采取措施来验证节点。如果您知道调用者并且知道这些节点总是被验证,那么我认为可以假设您将获得良好的数据。基本上责任在于呼叫者。
但是,如果您是,例如,提供分发的第三方库,则需要验证节点是否为空等...
illegalArugementException是java标准,但也是RunTimeException。因此,如果您想强制调用者处理异常,那么您需要提供一个检查异常,可能是您创建的自定义异常。
答案 7 :(得分:1)
我个人认为NullPointerExceptions只是意外发生,因此必须使用其他东西来表明传递了非法的参数值。 IllegalArgumentException对此很好。
if (arg1 == null) {
throw new IllegalArgumentException("arg1 == null");
}
对于那些阅读代码的人来说,这应该足够了,但也应该是早上3点获得支持电话的穷人。
(并且,总是为您的例外情况提供解释性文字,你会感激他们一些悲伤的日子)
答案 8 :(得分:0)
喜欢另一个:java.lang.IllegalArgumentException。 关于检查null Node,在创建节点时检查错误输入怎么办?
答案 9 :(得分:0)
我不需要取悦任何人,所以我现在所做的规范代码是
void method(String s)
if((s != null) && (s instanceof String) && (s.length() > 0x0000))
{
让我睡不着觉。
其他人不同意。