它是这样的有几个原因。当然,从概念上讲,trySplit
它可能会回归Optional<Spliterator<T>>
,但有一些设计力量推动了这一点。
findFirst
一个原因是,诸如return之类的Optional
方法与诸如trySplit
return value-or-null之类的方法之间存在差异。
- 诸如此类
findFirst
的方法由应用程序代码调用并将值返回给应用程序代码。
- 类似
trySplit
的方法由库代码调用并将值返回给库代码。
JDK 类库的一个设计方面是库 API 被(或应该)设计为使应用程序代码更容易,并且库代码通常会变得更复杂,以使应用程序更简单。
的主要原因之一Optional
是避免将空值从库传递到应用程序代码,因为不正确的空值处理是NullPointerException
s 的常见来源。取而代之的是null
,APIfindFirst
将返回一个空的Optional
,它由一组丰富的方法支持,例如orElse
、map
、filter
、flatMap
等,这些方法为应用程序处理未找到的情况提供了很大的灵活性。
请注意,可以为空的返回值从trySplit
相反的方向发展:从应用程序到库。
让应用程序代码向库传递或返回一个可为空的值比让应用程序从库中接收一个可为空的值更不容易出错。如果您正在编写一个应用程序并且 API 说您应该向库传递或返回 null,那么这不可能在您的代码中生成 NPE。实际上,API 中有很多地方(List.sort(null)
想到)在null
API 中有特定的语义。
trySplit
从库中相对较少的地方调用,并且库维护人员正在承担null
在所有这些情况下正确处理的负担。
另一个主要考虑因素是性能。拆分是建立并行管道的关键路径。它是按顺序执行的,然后将工作移交给不同的线程以并行执行。根据Amdahl 定律,为了使并行性尽可能高效,您希望最小化顺序设置开销。
事实是 anOptional
是一个盒子,将一个值装箱和拆箱是有成本的Optional
。在某些情况下, JIT 编译器可能会优化它,但它可能不会。即使是这样,也有一段时间代码正在运行但Optional
尚未优化。这是额外的开销。由于库代码愿意承担正确处理的负担,我们可以保证在这种情况下null
根本不使用就不会产生装箱开销。Optional