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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/411447/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:19:19  来源:igfitidea点击:

How to show if a method may return null

javanulldesign-by-contract

提问by Lena Schimmel

After posting this questionand reading that oneI 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 .

在发布了这个问题并阅读了那个问题之后我意识到知道一个方法是否应该返回 null,或者这是否被认为是一个错误条件并且应该抛出异常是非常重要的。还有一个很好的讨论何时返回 '​​null' 或 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?

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

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 throwsan exception will notreturn null, and every one that does 'not' throw mightreturn null.
  • 把它写在规范/文档中(有人会读吗?)
  • 使其成为方法名称的一部分(正如我在这里建议的那样)
  • 假设每个抛出异常的方法都不会返回 null,并且每个“不”抛出的方法都可能返回 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 throwskeywords) but no formal way to express if null might be returned?

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

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 @NotNullbecause it is visible to the programmer and can be used for automated compile time checking. There's a plugin for Eclipseto 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 nullabilityof 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.
  • 如果您的 IDE 支持它(如 IntelliJ),最好使用类似的注释,@NotNull因为它对程序员是可见的,并且可用于自动编译时检查。Eclipse有一个插件来添加对这些的支持,但它对我不起作用。
  • 如果这些不是一个选项,请使用自定义类型,如Option<T>NotNull<T>,这会增加清晰度和至少运行时检查。
  • 无论如何,在 JavaDoc 中记录合同永远不会受到伤害,有时甚至会有所帮助。
  • 使用方法名称来记录返回值的可空性不是由我以外的任何人提出的,尽管它可能非常冗长且并不总是有用,但我仍然相信有时它也有其优点。

采纳答案by Ronald Blaschke

A very good follow up question. I consider nulla truly special value, and if a method may return nullit 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 return nullunless I'm convinced it can't (e.g., because the Javadoc said so.)

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

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 Typesand JetBrain's Nullable How-To.

人们意识到这是一个问题,建议的解决方案是使用注释以一种可以自动检查的方式来陈述意图。请参阅JSR 305:软件缺陷检测注释JSR 308:Java 类型注释JetBrain 的 Nullable How-To

Your example might look like this, and refused by the IDE, the compiler or other code analysis tools.

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

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

回答by Ray Booysen

Have you had a look at Spec#?

你看过Spec#吗?

回答by Jon Skeet

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 contractsfor this sort of thing) but it would at least act as documentation.

您可以编写自己的注释 (Java) 或属性 (C#) 来指示返回值可能为空。没有任何东西会自动检查它(尽管 .NET 4.0 会有此类事情的代码合同),但它至少可以作为文档。

回答by Apocalisp

You can use the Optiontype, which is very much like a list that has zero or one element. A return type of Option<Object>indicates that the method may return an Object, or it may return a special value of type None. This type is a replacement for the use of null with better type checks.

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

Example:

例子:

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

If you use this consistently, you can turn on IDE null-warnings, or just use grep for nullwhich should not appear in your code at all if you use Option.none()everywhere you would normaly use a nullliteral.

如果你一直使用它,你可以打开 IDE 空警告,或者只使用 grep ,null如果你在任何Option.none()地方使用你通常会使用null文字的地方,它根本不应该出现在你的代码中。

Optioncomes standard with Scala, and it is called Maybein Haskell. The link above is to a library called Functional Javathat includes it. That version implements the Iterableinterface, and has monadic methods that let you compose things nicely. For example, to provide a default value of 0 in case of None:

OptionScala 是标准的,它Maybe在 Haskell 中被调用。上面的链接是一个名为Functional Java的库,其中包含它。该版本实现了Iterable接口,并具有可让您很好地组合事物的 monadic 方法。例如,在以下情况下提供默认值 0 None

int x = optionalInt.orSome(0);

And you can replace this...

你可以更换这个...

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

...with this, if you have an Option<String>...

......有了这个,如果你有Option<String>......

for (String s : myOptionString)

回答by opyate

If you're using Java 5+, you can use a custom Annotation, e.g. @MayReturnNull

如果您使用的是 Java 5+,则可以使用自定义注释,例如 @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、使用异常、断言、yada yada),我希望以上内容能回答您的问题。除了具有默认值的原语外,复杂类型可能为也可能不为空,您的代码需要处理它。

回答by Joachim Sauer

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.

IntelliJ IDEA支持@Nullable 和 @NotNull 注释。还有一些关于将这些注释(或类似功能)添加到 Java 7 的讨论。不幸的是,我不知道这已经走了多远,或者它是否仍然在正轨上。

回答by xtofl

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:

我看到三个选项:

  1. wait for language support to express it (e.g. the C# ?!thing)
  2. use Aspect Orientation to build your own language extensions to express it
  3. use a custom type to express it
  4. (but builds on developer cooperation) use a naming scheme to indicate it
  1. 等待语言支持来表达它(例如C# ?!东西)
  2. 使用 Aspect Orientation 构建您自己的语言扩展来表达它
  3. 使用自定义类型来表达它
  4. (但建立在开发人员合作的基础上)使用命名方案来表示它

回答by ChrisW

Maybe you could define a generic class named "NotNull", so that your method might be like:

也许你可以定义一个名为“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);
}

This is still a run-time (not a compile-time) check, but:

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

  • It's thrown in the implementation of the method (it's not a fault in the calling code)
  • It's self-documenting (the caller knows he's geting NotNull<T>as a return type)
  • 是在方法的实现中抛出的(不是调用代码的错误)
  • 它是自我记录的(调用者知道他是NotNull<T>作为返回类型获取的)

回答by Ross

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.

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

If you cannot design your API in such a way, I would clearly document when and why a null could be thrown--at leastin the Javadoc, and possibly also using a custom @annotation such as several of the other answers have suggested.

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

回答by joel.neely

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.

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

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).

另一方面,我承认我不认为 null 是可怕的。在某些情况下,“没有人的家”是一个有意义的条件(尽管空对象技术在这里也有实际价值)。

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.

尝试对空值进行方法调用肯定会导致异常。但是试图除以零也是如此。这并不意味着我们需要开展一场消除零的运动!这只是意味着我们需要理解一个方法的契约,并用它返回的值做正确的事情。