我在 java.util.Spliterator
(Java 8) 中偶然发现了一个有趣的细节。
方法 trySplit() 应该返回 Spliterator 的实例或 null
,如果它不能被拆分。 Java 文档说明如下:
* @return a {@code Spliterator} covering some portion of the
* elements, or {@code null} if this spliterator cannot be split.
在我看来,它是使用 java.util.Optional
的完美场所。根据 javadoc:
* A container object which may or may not contain a non-null value.
有什么原因,为什么没有使用 Optional?
谷歌搜索没有太大帮助,除了这个 question在 lambda-dev 邮件列表中,没有得到答复。
最佳答案
之所以会这样,有几个原因。当然,从概念上讲,trySplit
可以返回 Optional<Spliterator<T>>
,但有一些设计力量反对这一点。
一个原因是方法之间存在差异,例如 findFirst
返回 Optional
与 trySplit
等方法返回值或空值。
- 类似
findFirst
的方法由应用程序代码调用并返回值。 - 类似
trySplit
的方法由库代码调用并返回值。
JDK 类库的一个设计方面是库 API 旨在(或应该)使应用程序代码更容易,而库代码通常会变得更复杂,以使应用程序更简单。
Optional
的主要原因之一是为了避免将空值从库传递到应用程序代码,因为不正确的空值处理是 NullPointerException
的常见来源秒。而不是 null
, API 像 findFirst
将返回一个空的 Optional
,它得到了一组丰富的方法的支持,例如 orElse
, map
, filter
, flatMap
等,为应用程序处理未找到的情况提供了很大的灵 active 。
请注意 trySplit
的可空返回值正朝着相反的方向发展:从应用程序到库。
与让应用程序从库接收可为空值相比,让应用程序代码将可空值传递或返回到库对应用程序来说更不容易出错。如果您正在编写应用程序并且 API 指示您应该将 null 传递或返回到库,那么这将不可能在您的代码中生成 NPE。实际上,API 中有很多地方(想到 List.sort(null)
),其中 null
在 API 中具有特定的语义。
trySplit
从库中相对较少的地方调用,库维护者承担了正确处理 null
的负担。在所有这些情况下。
另一个主要考虑因素是性能。拆分是建立并行管道的关键路径。它按顺序执行,然后将工作移交给不同的线程以并行执行。每Amdahl's Law ,为了使并行性尽可能高效,您希望最小化顺序设置开销。
事实是 Optional
是一个盒子,将一个值装箱和拆箱到 Optional
是有成本的。 .在某些情况下,JIT 编译器可能能够优化它,但也可能不会。即使是这样,代码也会在一段时间内运行,但 Optional
还没有被优化掉。这是额外的开销。既然图书馆代码愿意承担处理重担null
正确地,我们可以通过不使用 Optional
来保证没有装箱开销在这种情况下完全没有。
关于java - Spliterator trySplit 返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30194584/