我们应该允许null / empty参数吗?

时间:2010-09-22 11:46:34

标签: parameters null code-contracts

我最近与同事讨论过是否应该允许将null或空集合作为方法参数传递。我的感觉是,这会导致异常,因为它会破坏方法的“契约”,即使它不一定会破坏方法的执行。这也具有“快速失败”的优点。我的同事辩称,这会导致代码乱丢“非空/非空”检查,即使它真的不重要。

我可以看到他的观点,但允许空或空参数让我感到不安。它可以通过延迟失败来隐藏问题的真正原因!

让我们举两个具体的例子:

1)鉴于我们有一个带有重叠(Interval)方法的Interval类,如果将null作为参数传递会发生什么?我的感觉是我们应该抛出一个IllegalArgumentException来让调用者知道某些东西可能是错误的,但我的同事觉得返回false是足够的,就像在他使用它的场景中一样,如果第二个Interval是是否为空(重要的是它们是否重叠)。

2)给定像fetchByIds(Collection ids)这样的方法,如果提供空集合会发生什么?再一次,我想警告打电话者发生了异常情况,但我的同事只是收到一个空列表就好了,因为他再一次不关心是否有任何ids。

被叫代码的责任在哪里结束?在这两种情况下,调用代码都不介意参数是null还是空,但在其他情况下,这可能指向可能的错误。一个方法是否只保证只要遵守先决条件就不会破坏,或者它是否应该尝试识别潜在的错误调用?

编辑:我看到很多很好的答案,大多数人倾向于将其定义为合同/在文档中并坚持使用它,但我希望你的意见何时允许它以及何时不允许(如果有的话) 。在具体的例子中,你会做什么?鉴于90%的用途,没有验证输入将是正常的,你仍然会验证清除剩余的10%中的错误,或者你更愿意解决它们出现的那些并避免不必要的空/空检查?< / p>

5 个答案:

答案 0 :(得分:6)

您的案例是两种不同的情况,可以很好地映射到现实世界:

  

1)鉴于我们有一个Interval类   使用重叠(Interval)方法,   如果传递null会发生什么   作为参数?我的感觉是   我们应该扔一个   允许IllegalArgumentException   来电者可能知道一些事情   错了,但我的同事觉得   返回false就足够了......

在这里传递null就像问“鸭子之间有什么区别?”,由于缺少信息,你无法回答。你不能说并且说“没有区别”,因为你不知道丢失的信息是另一只鸭子(没有差异)还是水牛(差异很大)。如果合同规定呼叫者必须提供可比较的内容并且呼叫者没有阻止其结束讨价还价,那么这就是抛出异常的理由。

  

2)给出一个类似的方法   fetchByIds(Collection ids),什么   如果是空集合应该会发生   提供了吗?

这类似于你的妻子告诉你从冰箱里取出购物清单并拿走它上面的所有东西。如果列表中没有任何内容(空集合),那么你什么都没回家,而且你完全按照你的要求行事。如果你去冰箱而没有找到购物清单(null),你会告诉你的妻子那里没有购物清单而提出例外,她可以决定她是否真的打算告诉你它在厨房的桌子或忘记整个事情。

  

一种方法应该只保证它   只要不会打破   遵守先决条件,或   它应该试图找出潜力   还有错误的调用吗?

正如其他人所说,该方法应该保证它的行为,但是它的文档表明它会表现。如果合同说该方法将在null参数存在时返回某个结果,则由调用者确定它知道它正在传递null并且能够处理结果。

如果程序在存在看似合理但有瑕疵的数据时应该如何表现取决于很多事情,例如它继续运作的重要性,或者继续处理这类数据是否会对还要别的吗。对于您,开发人员来说,这是一个决定,根据您的判断逐个进行。任何声称知道在任何情况下应始终采用单向方式的人都没有仔细研究过这个问题。

如果您选择不抛出异常(例如,为false返回overlaps(null)),您始终可以选择记录您看到的东西以及其他任何其他信息的事实有可用(堆栈跟踪等)。这使您可以选择在带外处理它,以便程序继续运行。

答案 1 :(得分:4)

许多主流语言(包括Java,C#和大多数脚本语言)的一个主要缺点是无法说“必须传递一个值!”我依旧回忆起对Hejlsberg的一次采访,他甚至承认这是他对C#的设计感到遗憾的一件事(省略了另一场灾难,IMO,但我们不要离题)。

这种美中不足的原因是你和你的同事对此事感到焦虑。没有解决方案(除非语言设计者能以某种方式改进修复)。两种选择都涉及妥协。一旦你们都意识到这一点,你就可以越早放松,只选择任何可以引起最小痛苦的事情。

就我而言,我赞成更强的合同,即使它们只能在运行时强制执行,因为这更接近于语言应该提供的不可为空的形式参数的概念。

答案 2 :(得分:3)

这确实是一个背景问题,没有好的答案。我会选择“最少惊喜”的原则。考虑使用代码的人:

  • 如果要在内部使用代码,请考虑将使用它的团队:他们是否知道如何处理潜在的异常?框架是否允许简单的异常处理?团队使用它吗?如果你是唯一一个担心这类问题的人,也许最好还是使用它并处理空的参数/列表

  • 如果您正在构建API,那么您几乎负责,但您必须保持一致。如果某些方法允许空参数而其他方法不允许,则可能是设计错误的标志。

  • 如果您正在构建一些代码来与UI进行交互,请确保用户界面有办法将错误归结为可理解的内容,并确保UI设计人员知道会发生什么。如果他们在用户列表为空时没有禁用“发送给用户”按钮,他们应该如何处理?

所以,对不起,我认为这里没有正确的方法。至于我,我会尽可能地去抛弃异常学校。

答案 3 :(得分:3)

我的一般方法是不接受null。空集合很好。

这些是一般规则,有些情况下违反这些规则是有意义的。在这些情况下,这就是方法文档的用途。该方法定义了合同,文档是精细打印。

答案 4 :(得分:2)

我想这没有对错,但是当你抛出一个异常时,这意味着发生了一些你无法恢复的无法预料的事情。例如,一个方法应该写一些东西到磁盘并且该磁盘已满...所以你应该问自己:有没有办法绕过这个问题而不抛出异常。另一个问题是这个功能还包含在这个类中吗?

例如,如果你有一个名为PrintList()的方法并且你有一个可以为null的参数,那么该方法是否有责任获取列表,然后打印它还是只打印它?也许应该更改方法的名称以包含此责任:GetAndPrintList()。

还要问问自己,如果将新成员添加到团队中会发生什么:他会在没有额外文档的情况下找到易于理解和阅读的代码吗?