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

在发布这个问题并阅读这个问题之后,我意识到知道一个方法应该返回null是非常重要的,或者如果这被认为是一个错误条件并且应该抛出一个exception。 还有一个很好的讨论何时返回“空”或抛出exception 。

我正在写一个方法,而且我已经知道如果我想要返回null还是抛出一个exception,那么expression我的决定的最好方法是什么,换句话说,就是要logging我的合同?

我可以想到的一些方法:

  • 写在规格/文档(任何人都可以阅读?)
  • 使其成为方法名称的一部分(正如我在这里所build议的)
  • 假设每一个引发exception的方法都不会返回null,而每一个“不”抛出的方法都会返回null。

我主要谈论java,但也可能适用于其他语言:为什么有一个正式的方式来表示如果抛出exception( throws关键字),但没有正式的方式来表示,如果null可能会返回?

为什么不存在这样的事情:

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

总结和结论

合同的expression方式有很多种:

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

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

人们意识到这是一个问题,build议的解决scheme是使用注释来expression意图,以便可以自动检查。 请参阅JSR 305:软件缺陷检测的注释 , JSR 308:Javatypes的注释和JetBrain的可空指导 。

你的例子可能看起来像这样,并被IDE,编译器或其他代码分析工具拒绝。

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

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

例:

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

如果你一致地使用这个,你可以打开IDE的空警告,或者只是使用grep for null ,如果你在任何地方使用了Option.none() ,那么通常就不会出现在你的代码中。

Option是Scala的标准,在Haskell中称为Maybe 。 上面的链接是一个名为Functional Java的库,包含它。 该版本实现了Iterable接口,并具有一些单方面的方法,可以让你很好地编写一些东西。 例如,要在None情况下提供默认值0:

 int x = optionalInt.orSome(0); 

你可以取代这个…

 if (myString != null && !"".equals(myString)) 

…如果你有一个Option<String>

 for (String s : myOptionString) 

事实上:在我们的框架中,我们有一个“非空”指针types,可能会返回指示该方法将始终返回一个值。

我看到三个选项:

  1. 等待语言支持来expression它(例如C#?!的东西)
  2. 使用Aspect Orientation来构build自己的语言扩展来expression它
  3. 使用自定义types来expression它
  4. (但build立在开发者合作之上)使用命名scheme来表示它

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

另一方面,我承认我并不认为“零”是值得担忧的。 有些情况下,“无人的家”是一个有意义的条件(尽pipe空对象技术在这里也有实际价值)。

当然,尝试对null值进行方法调用肯定会导致exception。 但是也会试图用零除。 这并不意味着我们需要去消除零的运动! 这只是意味着我们需要理解一个方法的合同,并用它返回的值做正确的事情。

你看过Spec#吗?

IntelliJ IDEA中支持@Nullable和@NotNull注释 。 还有一些关于将这些注释(或类似function)添加到Java 7的讨论。不幸的是,我不知道它到底有多远,或者它是否仍在运行。

也许你可以定义一个名为“NotNull”的generics类,这样你的方法可能是这样的:

 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); } 

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

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

不惜一切代价,避免依赖JavaDocs。 如果签名没有显得微不足道和不言自明(这是不好的开始),而且这些实际上阅读它们的人不太可能与空值犯错,因为他们现在正在更加小心。

您可以编写自己的注释(Java)或属性(C#)来指示返回值可能为空。 没有东西会自动检查它(尽pipe.NET 4.0将会有这样的代码合约 ),但它至less可以作为文档。

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

UPDATE

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

一般来说,我会假设一个空的返回值是默认违反API的合约。 几乎总是可以devise代码,以便在“正常”执行stream程期间不会从API中返回空值。 (例如,检查foo.contains(obj)而不是调用foo.get(obj),并为null创build一个单独的分支,或者使用Null对象模式 。

如果你不能以这种方式devise你的API,我会清楚地logging什么时候和为什么会抛出一个null – 至less在Javadoc中,并且可能还使用一个自定义的@annotation,如其他几个答案所build议的。