在发布this question并阅读that one之后,我意识到知道一个方法是否应该返回null,或者如果这被视为错误条件并且应该抛出异常,这一点非常重要。什么时候对return ‘null’ or throw exception 进行了很好的讨论。
我正在编写一个方法,我已经知道是否要返回null或抛出异常,表达我的决定的最佳方式是什么,换句话说,记录我的合同?
我能想到的一些方法:
我主要讨论java,但它也可能适用于其他语言:为什么有一种正式的方式来表达是否会抛出异常(throws
关键字)但没有正式的方式来表达可能会返回null吗?
为什么没有这样的东西:
public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
return null; // this would lead to a compiler error!
}
有很多方式来表达合同:
@NotNull
的注释,因为它对程序员可见,并可用于自动编译时检查。有一个plugin for Eclipse来添加对这些的支持,但它对我不起作用。Option<T>
或NotNull<T>
等自定义类型,这样可以增加清晰度,至少可以进行运行时检查。答案 0 :(得分:35)
一个非常好的跟进问题。我认为null
是一个真正特殊的值,如果一个方法可能返回null
,它必须在Javadoc中明确记录(@return some value ..., or null if ...
)。在编码时我是防御性的,并假设一种方法可能会返回null
,除非我确信它不能(例如,因为Javadoc这样说。)
人们意识到这是一个问题,并且建议的解决方案是使用注释以可以自动检查的方式陈述意图。请参阅JSR 305: Annotations for Software Defect Detection,JSR 308: Annotations on Java Types和JetBrain'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);
:
if (myString != null && !"".equals(myString))
你可以替换这个......
Option<String>
...如果您有for (String s : myOptionString)
...
{{1}}
答案 2 :(得分:2)
确实:在我们的框架中,我们有一个'非null'指针类型,可以返回它以指示该方法将始终返回一个值。
我看到三个选项:
答案 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等正如其他几个答案所暗示的那样。