如何显示方法是否可以返回null

时间:2009-01-04 18:30:16

标签: java null design-by-contract

在发布this question并阅读that one之后,我意识到知道一个方法是否应该返回null,或者如果这被视为错误条件并且应该抛出异常,这一点非常重要。什么时候对return ‘null’ or throw exception 进行了很好的讨论。

我正在编写一个方法,我已经知道是否要返回null或抛出异常,表达我的决定的最佳方式是什么,换句话说,记录我的合同?

我能想到的一些方法:

  • 在规格/文档中写下来(有人会阅读吗?)
  • 将其作为方法名称的一部分(正如我建议here
  • 假设抛出异常的每个方法都返回null,而每个“不”抛出的方法可能返回null。

我主要讨论java,但它也可能适用于其他语言:为什么有一种正式的方式来表达是否会抛出异常(throws关键字)但没有正式的方式来表达可能会返回null吗?

为什么没有这样的东西:

public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

摘要和结论

有很多方式来表达合同:

  • 如果您的IDE支持它(作为IntelliJ),最好使用类似@NotNull的注释,因为它对程序员可见,并可用于自动编译时检查。有一个plugin for Eclipse来添加对这些的支持,但它对我不起作用。
  • 如果这些不是一个选项,请使用Option<T>NotNull<T>等自定义类型,这样可以增加清晰度,至少可以进行运行时检查。
  • 无论如何,在JavaDoc中记录合同永远不会伤害,有时甚至会有帮助。
  • 除了我之外,没有人提出使用方法名来记录返回值的可空性,虽然它可能非常详细而且并不总是有用,但我仍然相信它有时会有其优点,太

11 个答案:

答案 0 :(得分:35)

一个非常好的跟进问题。我认为null是一个真正特殊的值,如果一个方法可能返回null,它必须在Javadoc中明确记录(@return some value ..., or null if ...)。在编码时我是防御性的,并假设一种方法可能会返回null,除非我确信它不能(例如,因为Javadoc这样说。)

人们意识到这是一个问题,并且建议的解决方案是使用注释以可以自动检查的方式陈述意图。请参阅JSR 305: Annotations for Software Defect DetectionJSR 308: Annotations on Java TypesJetBrain's Nullable How-To

您的示例可能如下所示,并被IDE,编译器或其他代码分析工具拒绝。

@NotNull
public Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

答案 1 :(得分:8)

您可以使用Option类型,这非常类似于具有零个或一个元素的列表。返回类型Option<Object>表示该方法可能返回Object,或者它可能返回类型None的特殊值。这种类型可以替代使用null和更好的类型检查。

示例:

public Option<Integer> parseInt(String s) {
   try {
      return Option.some(Integer.parseInt(s));
   }
   catch (Exception e) {
      return Option.none();
   }
}

如果您始终如一地使用此功能,则可以启用IDE无效警告,或者只使用null的grep,如果您使用Option.none()所有地方,您应该使用null一个Option字面值。

Maybe是Scala的标准配置,在Haskell中称为Iterable。上面的链接指向包含它的名为Functional Java的库。该版本实现了None接口,并具有monadic方法,可以让您很好地组合。例如,要在int x = optionalInt.orSome(0);

的情况下提供默认值0
if (myString != null && !"".equals(myString))

你可以替换这个......

Option<String>

...如果您有for (String s : myOptionString) ...

,请使用此功能
{{1}}

答案 2 :(得分:2)

确实:在我们的框架中,我们有一个'非null'指针类型,可以返回它以指示该方法将始终返回一个值。

我看到三个选项:

  1. 等待语言支持表达它(例如C# ?!事物)
  2. 使用Aspect Orientation构建您自己的语言扩展来表达它
  3. 使用自定义类型表达
  4. (但建立在开发者合作的基础上)使用命名方案来表明它

答案 3 :(得分:2)

对于Java,可以使用方法的Javadoc描述来记录返回值的含义,包括它是否可以为null。如前所述,注释也可以在这里提供帮助。

另一方面,我承认我不认为null是值得担心的事情。在某些情况下,“没有人的家”是一个有意义的条件(虽然Null对象技术在这里也有实际价值)。

尝试对null值进行方法调用肯定会导致异常。但是也会试图除以零。这并不意味着我们需要继续开展消除零的活动!它只是意味着我们需要理解方法上的契约,并使用它返回的值做正确的事。

答案 4 :(得分:1)

你看过Spec#吗?

答案 5 :(得分:1)

您可以编写自己的注释(Java)或属性(C#)来指示返回值可能为null。什么都不会自动检查它(虽然.NET 4.0对于这类事情会有code contracts)但它至少会充当文档。

答案 6 :(得分:1)

@Nullable and @NotNull annotation in IntelliJ IDEA有一些支持。还有一些关于将这些注释(或类似功能)添加到Java 7的讨论。遗憾的是,我不知道它到底有多远,或者它是否仍然在轨道上。

答案 7 :(得分:1)

也许你可以定义一个名为“NotNull”的泛型类,这样你的方法可能就像:

public NotNull<Object> methodWhichCannotReturnNull(int i) throws Exception
{
   // the following would lead to a run-time error thown by the
   // NotNull constructor, if it's constructed with a null value
   return new NotNull<Object>(null);
}

这仍然是运行时(不是编译时)检查,但是:

  • 它抛出在方法的实现中(这不是调用代码中的错误)
  • 它是自我记录的(来电者知道他将NotNull<T>作为返回类型)

答案 8 :(得分:1)

不惜一切代价,避免依赖JavaDocs。如果签名看起来并不简单且不言自明(开头不好),人们只会阅读它们,而那些实际上懒得阅读它们的人不太可能犯空错误,因为他们现在更加小心。

答案 9 :(得分:0)

如果您使用的是Java 5+,则可以使用自定义注释,例如@MayReturnNull

<强>更新

除了所有编码原理(返回null,使用异常,断言,yada yada),我希望上面的答案是你的问题。除了具有默认值的基元之外,复杂类型可能为空,也可能不为空,并且您的代码需要处理它。

答案 10 :(得分:0)

一般来说,我认为默认情况下,null返回值是违反API的合同的。几乎总是可以设计代码,以便在“正常”执行流程期间永远不会从API返回空值。 (例如,检查foo.contains(obj)而不是调用foo.get(obj)并为null设置单独的分支。或者,使用Null object pattern

如果你不能以这种方式设计你的API,我会清楚地记录何时以及为什么抛出null - 在Javadoc中的至少,并且可能还使用自定义@annotation等正如其他几个答案所暗示的那样。