简短的回答是:
这取决于具体情况。
更具体地说,这个问题无法一般性地回答,需要看整个类并了解其设计。空检查是实现细节,在某些设计中是合适的,但在其他设计中可能是有问题的。
总的来说,
方法必须遵守其契约,不能超出范围。因此,从 API 设计的角度来看,这个问题是不相关的。你应该根据一长串现有的最佳实践来设计你的 API,然后再设计你的实现以适应它。其中一个最佳实践是,在返回
Collection
时不要将“零元素”特殊处理为
null
。也就是说,如果你的方法可以合理地返回一个空集合,
它应该返回一个空集合,而不是一个特殊值,比如
null
。这几乎总是简化客户端代码,并消除了一整类潜在的 NPEs。这并不意味着你不能在内部使用
null
来标记“零元素”,但这意味着如果你这样做了,你应该在返回时执行转换(如你的示例中所示)。
因此,如果您的
getTasks()
方法指定它始终返回一个(可能为空的)列表,则像您的示例中使用null检查是合理的实现选择。在您具体的示例中,这可能不是最佳选择,因为JDK提供了像
Collections.emptyList<T>()
这样的方法,允许您廉价地重用单例空列表实例,因此您在内存方面没有任何节省,并且CPU节省是可疑的
1。
此外,通过使用“
null
表示空列表”的约定,您要求所有内部方法都必须检查
tasks == null
,否则使用getTasks()方法。在集合对象的
特定情况中,我通常更喜欢使用
Collections.empty*
方法而不是null来表示空列表
2。类似的推理适用于
Integer
情况,因为
Integer.valueOf(0)
在
所有兼容的JVM上返回一个单例对象。
除了那些特殊情况,当没有好的“空”元素存在或性能很重要时,确实有理由使用空检查来表示缺失或默认元素。你会发现这种模式在设计良好的库中被频繁使用,例如Java运行时和Guava。因此,不能说这是一种不好的做法。它是一种需要仔细评估的做法。
1这些Collection.empty*
方法的使用也适用于您的示例。在您的空值情况下,您可以考虑直接返回Collections.emptyList()
,而不是按需创建新的ArrayList
。是否适当取决于整个类设计,例如该列表是否可变。
2Collections.emptyList()
是否比显式的空检查更快实际上是一个复杂的问题。如果空列表很少在给定进程中出现,那么emptyList()
方法可能更快,因为其成本(相对于getter)随着空列表频率趋近于零而变为零。另一方面,当空列表确实出现时,它可能会为使用List
的所有方法创建多态调用站点:每个这样的站点都可能看到特殊的“空列表”实现和ArrayList
。这可能会减慢代码,尽管很多取决于内联决策。因此,像通常的性能考虑一样,确切的答案是复杂的,需要进行分析,如果细节很重要。
getMinutes
返回一个int
(问题解决了,null 本来就是一个错误的值),并且总是在构造函数中或直接声明时初始化列表。 - Tunaki