发布后 这个问题并阅读那个 我意识到知道一个方法是否应该返回 null,或者这是否被认为是错误条件并且应该抛出异常是非常重要的。 还有一个很好的讨论何时返回“null”或抛出异常。
我正在编写一个方法,并且我已经知道是否要返回 null 或引发异常,表达我的决定(换句话说,记录我的合同)的最佳方式是什么?
可以想到:
- 将其写在规范/文档中(有人会读吗?)
- 将其作为方法名称的一部分(正如我建议的此处)
- 假设每个抛出异常的方法不会返回 null,而每个“不”抛出可能返回 null。
我主要讨论的是 java,但它也可能适用于其他语言:Why is there a permanent way to express if例外将被抛出( throws
keywords),但没有正式的方式来表达 if可能会返回null?
为什么没有这样的东西:
public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
return null; // this would lead to a compiler error!
}
总结和结论
有很多方法可以表达契约:
- 如果您的 IDE 支持它(如 IntelliJ),最好使用像
@NotNull
这样的注释,因为它是对程序员可见,可用于自动编译时检查。 有一个Eclipse 插件来添加对这些的支持,但它没有为我工作。
- 如果这些不是一个选项,请使用自定义类型,例如
Option
或 NotNull
,这会增加清晰度并至少增加运行时检查。
- 无论如何,在 JavaDoc 中记录契约从来没有坏处,有时甚至有帮助。
- 除了我之外,没有人提议使用方法名称来记录返回值的可空性,尽管它可能非常冗长且并不总是有用,但我仍然相信有时它也有其优点。
After posting this question and reading that one I realized that it is very important to know if a method is supposed to return null, or if this is considered an error condition and an exceptions should be thrown. There also is a nice discussion when to return ‘null’ or throw exception .
I'm writing a method and I already know if I want to return null or throw an exception, what is the best way to express my decision, in other words, to document my contract?
Some ways I can think of:
- Write it down in the specs / the documentation (will anyone read it?)
- Make it part of the method name (as I suggested here)
- assume that every method that throws an exception will not return null, and every one that does 'not' throw might return null.
I'm mainly talking about java, but it might apply to other languages, too: Why is there a formal way to express if exceptions will be thrown (the throws
keywords) but no formal way to express if null might be returned?
Why isn't there something like that:
public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
return null; // this would lead to a compiler error!
}
Summary and Conclusion
There are many ways to express the contract:
- If your IDE supports it (as IntelliJ), it's best to use an annotation like
@NotNull
because it is visible to the programmer and can be used for automated compile time checking. There's a plugin for Eclipse to add support for these, but it didn't work for me.
- If these are not an option, use custom Types like
Option<T>
or NotNull<T>
, which add clarity and at least runtime checking.
- In any way, documenting the contract in the JavaDoc never hurts and sometimes even helps.
- Using method names to document the nullability of the return value was not proposed by anyone but me, and though it might be very verbose und not always useful, I still believe sometimes it has its advantages, too.
发布评论
评论(11)
一个非常好的后续问题。 我认为
null
是一个真正特殊的值,如果一个方法可能返回null
,那么它必须在 Javadoc 中清楚地记录它的情况(@return some value ... ,或 null 如果...
)。 在编码时,我是防御性的,并假设一个方法可能返回 null ,除非我确信它不能(例如,因为 Javadoc 是这么说的)。人们意识到这是一个问题,并且建议的解决方案是使用注释以可以自动检查的方式来陈述意图。 请参阅JSR 305:软件缺陷检测注释、JSR 308:Java 类型注释 和 JetBrain 的可为空操作方法。
您的示例可能如下所示,并被 IDE、编译器或其他代码分析工具拒绝。
A very good follow up question. I consider
null
a truly special value, and if a method may returnnull
it must clearly document in the Javadoc when it does (@return some value ..., or null if ...
). When coding I'm defensive, and assume a method may returnnull
unless I'm convinced it can't (e.g., because the Javadoc said so.)People realized that this is an issue, and a proposed solution is to use annotations to state the intention in a way it can be checked automatically. See JSR 305: Annotations for Software Defect Detection, JSR 308: Annotations on Java Types and JetBrain's Nullable How-To.
Your example might look like this, and refused by the IDE, the compiler or other code analysis tools.
您可以使用
选项
< /a> 类型,它非常类似于具有零个或一个元素的列表。Option
示例:
如果您始终使用此选项,则可以打开 IDE null 警告,或者仅使用 grep 来处理
null
,如果您使用Option.none(),则该警告根本不应该出现在您的代码中
在通常使用null
文字的地方。Option
是 Scala 的标准配置,在 Haskell 中称为Maybe
。 上面的链接是一个名为 Functional Java 的库,其中包含它。 该版本实现了 Iterable 接口,并具有可让您很好地组合事物的一元方法。 例如,在None
的情况下提供默认值 0:您可以用此替换...
如果您有
Option
, ... >...You can use the
Option
type, which is very much like a list that has zero or one element. A return type ofOption<Object>
indicates that the method may return anObject
, or it may return a special value of typeNone
. This type is a replacement for the use of null with better type checks.Example:
If you use this consistently, you can turn on IDE null-warnings, or just use grep for
null
which should not appear in your code at all if you useOption.none()
everywhere you would normaly use anull
literal.Option
comes standard with Scala, and it is calledMaybe
in Haskell. The link above is to a library called Functional Java that includes it. That version implements theIterable
interface, and has monadic methods that let you compose things nicely. For example, to provide a default value of 0 in case ofNone
:And you can replace this...
...with this, if you have an
Option<String>
...IntelliJ IDEA 中对 @Nullable 和 @NotNull 注释提供了一些支持。 还有一些关于将这些注释(或类似功能)添加到 Java 7 的讨论。不幸的是,我不知道这已经进展到什么程度,也不知道它是否仍然在正轨上。
There's some support for a @Nullable and @NotNull annotation in IntelliJ IDEA. There's also some talk about adding those annotations (or a similar feature) to Java 7. Unfortunately I don't know how far that got or if it's still on track at all.
事实上:在我们的框架中,我们有一个“非空”指针类型,它可以被返回以指示该方法将始终返回一个值。
我看到三个选项:
Indeed: in our framework we have a 'non-null' pointer type, which may be returned to indicate that the method will always return a value.
I see three options:
对于 Java,可以使用方法的 Javadoc 描述来记录返回值的含义,包括它是否可以为 null。 正如已经提到的,注释也可以在这里提供帮助。
另一方面,我承认我并不认为 null 是值得害怕的东西。 在某些情况下,“无人在家”是一个有意义的条件(尽管空对象技术在这里也具有实际价值)。
尝试对空值进行方法调用确实会导致异常。 但尝试除以零也是如此。 这并不意味着我们需要开展消除零的运动! 这只是意味着我们需要理解方法上的约定,并利用它返回的值做正确的事情。
For Java, one can use the Javadoc description of a method to document the meaning of the returned value, including whether it can be null. As has been mentioned, annotations may also provide assistance here.
On the other hand, I admit that I don't see null as something to be feared. There are situations in which "nobody's home" is a meaningful condition (although the Null Object technique also has real value here).
It is certainly true that attempting a method invocation on a null value will cause an exception. But so will attempting to divide by zero. That doesn't mean that we need to go on a campaign to eliminate zeroes! It just means that we need to understand the contract on a method and do the right thing with the values that it returns.
不惜一切代价,避免依赖 JavaDocs。 人们只有在签名看起来不琐碎且不言自明的情况下才会阅读它们(这从一开始就很糟糕),而那些真正费心阅读它们的人不太可能在空值上犯错误,因为他们目前更加小心。
At all costs, avoid relying on the JavaDocs. People only read them if the signature doesn't appear trivial and self-explanatory (Which is bad to begin with), and these who actually bother to read them are less likely to make a mistake with the nulls since they are currently being more careful.
您是否看过Spec#?
Have you had a look at Spec#?
您可以编写自己的注释 (Java) 或属性 (C#) 来指示返回值可能为 null。 没有任何东西会自动检查它(尽管 .NET 4.0 将具有代码契约这类事情)但它至少可以充当文档。
You could write your own annotation (Java) or attribute (C#) to indicate that the return value might be null. Nothing will automatically check it (although .NET 4.0 will have code contracts for this sort of thing) but it would at least act as documentation.
也许您可以定义一个名为“NotNull”的泛型类,以便您的方法可能类似于:
这仍然是运行时(不是编译时)检查,但是:
NotNull
作为返回类型)Maybe you could define a generic class named "NotNull", so that your method might be like:
This is still a run-time (not a compile-time) check, but:
NotNull<T>
as a return type)如果您使用的是 Java 5+,您可以使用自定义注释,例如 @MayReturnNull
UPDATE
抛开所有编码哲学(返回 null、使用异常、断言、yada yada),我希望以上回答您的问题问题。 除了具有默认值的基元之外,复杂类型可能为空,也可能不为空,并且您的代码需要处理它。
If you're using Java 5+, you can use a custom Annotation, e.g. @MayReturnNull
UPDATE
All coding philosophy aside (returning null, using exceptions, assertions, yada yada), I hope the above answers your question. Apart from primitives having default values, complex types may or may not be null, and your code needs to deal with it.
一般来说,我会假设默认情况下返回 null 值是违反 API 约定的。 几乎总是可以将代码设计为在“正常”执行流程期间永远不会从 API 返回空值。 (例如,检查 foo.contains(obj) 而不是调用 foo.get(obj) 并为 null 建立一个单独的分支。或者,使用 空对象模式。
如果您无法以这种方式设计 API,我会清楚地记录何时以及为何会抛出空值 - 至少在 Javadoc 中,也可能使用自定义 @annotation,如其他几个答案所建议的那样。
Generally speaking, I would assume that a null return value is against the contract of the API by default. It is almost always possible to design your code such that a null value is never returned from your APIs during "normal" flow of execution. (For example, check foo.contains(obj) rather then calling foo.get(obj) and having a separate branch for null. Or, use the Null object pattern.
If you cannot design your API in such a way, I would clearly document when and why a null could be thrown--at least in the Javadoc, and possibly also using a custom @annotation such as several of the other answers have suggested.