Java:可选的可选实现
類java.util.Optional被實現(xiàn)為單個不可變的具體類,該類在內部處理兩種情況。 一個有元素,一個沒有元素。 讓Optional作為一個接口并讓兩個不同的實現(xiàn)代替實現(xiàn)是一個更好的選擇嗎? 畢竟,這就是我們通常被教導要使用的一種面向對象的語言。
在本文中,我們將了解當前Optional實現(xiàn)的一些潛在參數(shù)。 我們還將學習為什么以不同的方式實現(xiàn)Streams,從而使Streams可以從文件甚至數(shù)據庫表中獲取。
真正的可選實現(xiàn)
真正的java.util.Optional::get實現(xiàn)如下所示:
public T get() { if (value == null ) { throw new NoSuchElementException( "No value present" ); } return value; }可以看出,有兩個代碼路徑。 一種是值是null(沒有元素,并且不會引發(fā)異常),另一種是值是其他值(返回值)。
可選可選實現(xiàn)
讓我們假裝我們將回到一臺時光機,并被要求再次實現(xiàn)Optional 。 我認為我們中的許多人可能會提出一個初始解決方案,就像下面的解決方案(我將其命名為假設接口Option以便我們可以將其與“實際”接口分開)有兩個截然不同的實現(xiàn)(此處為EmptyOption和PresentOption ):
public interface Option<T> { T get(); boolean isPresent(); public <U> Option<U> map(Function<? super T, ? extends U> mapper); static <T> Option<T> empty() { return (Option<T>) EmptyOption.EMPTY; } (Option<T>) EmptyOption.EMPTY; } <T> Option<T> of(T value) { static <T> Option<T> of(T value) { return new PresentOption<>(value); } PresentOption<>(value); } <T> Option<T> ofNullable(T value) { static <T> Option<T> ofNullable(T value) { return value == null ? empty() : of(value); ? empty() : of(value); } } final class EmptyOption<T> implements Option<T> { static final EmptyOption<?> EMPTY = new EmptyOption<>(); private EmptyOption() {} @Override public T get() { throw new NoSuchElementException(); } NoSuchElementException(); } @Override public boolean isPresent() { return false ; } ; } @Override public <U> Option<U> map(Function<? super T, ? extends U> mapper) { requireNonNull(mapper); return (Option<U>) EMPTY; } } final class PresentOption<T> implements Option<T> { private final T value; PresentOption(T value) { this .value = requireNonNull(value); } .value = requireNonNull(value); } @Override public T get() { return value; } value; } @Override public boolean isPresent() { return true ; } ; } @Override public <U> Option<U> map(Function<? super T, ? extends U> mapper) { requireNonNull(mapper); return Option.ofNullable(mapper.apply(value)); } }為了簡潔起見,僅示出了幾種方法,但是原理保持不變:針對存在元素和不存在元素的情況的不同實現(xiàn)。 這給出了更清晰的代碼,也使任何人都可以實現(xiàn)可選選項。
分析
我有信心,在設想Optional時,JDK團隊已對這種解決方案進行了評估,我認為這是明智的決定,不選擇這種解決方案。 Optional主要目的是“包裝”返回值,以防止NPE和返回原始空值的其他缺點。 我還認為設計目標是使用Optional對性能的影響應該很小或可以忽略不計。
在下文中,我推測了一些論點,以選擇上述可選實現(xiàn)為基礎的當前Optional實現(xiàn)。
剖面污染
JIT編譯器按需編譯Java字節(jié)碼,以提高解釋字節(jié)碼的性能。
為了有效地做到這一點,JIT編譯器能夠收集每種已知方法的統(tǒng)計信息。 每個方法都可以具有一個MethodData對象,該對象包含有關如何使用該方法的度量,并且一旦JVM認為該方法足夠“溫暖”(即在某種意義上已被充分調用),便會創(chuàng)建該對象。
創(chuàng)建和維護MethodData過程稱為“分析”。
當調用之間使用的方法大不相同時,就會發(fā)生“配置文件污染”,包括但不限于提供交替的非null / null元素并調用不同的多態(tài)方法(例如,參數(shù)是T類型的泛型,并且被調用的方法調用T::equals )。 Java的基本功能是其動態(tài)調用方法的能力。 因此,當調用Option::get時, EmptyOption::get或
最終調用PresentOption::get取決于調用時存在的實現(xiàn)。
一旦該方法被調用了10,000次,JIT編譯器就會使用MethodData創(chuàng)建一個有效的已編譯代碼段,根據迄今為止收集的統(tǒng)計信息,該代碼段將以最佳方式執(zhí)行。
因此,如果元素始終存在(使用PresentOption ),并且牢記這一點來編譯代碼,但隨后突然出現(xiàn)EmptyOption ,則代碼必須“退出”并采用慢得多的代碼路徑。
僅在最后一個類中使用Optional ,就不可能再有Optional方法的任何其他實現(xiàn),因此,不會因不同的實現(xiàn)而造成配置文件污染。 JIT可以確定性且合理地快速確定編譯的代碼。
但是,等等,JVM不可能在啟動時檢查所有類并確定實際上只有兩個實現(xiàn)類。
Option ,然后它可以解決整個問題? 好吧,不。 我們可以隨時隨意添加類,因此無法安全地枚舉特定接口的所有可能實現(xiàn)。 至少要等到我們有了真正的Java密封類時,才能進行。
原料藥污染
如果人們可以自由編寫Optional自定義實現(xiàn),那么與內置Optional相比,這些實現(xiàn)很可能會遭受設計缺陷/偏差。 同樣,人們可能會讓他們自己的類型實現(xiàn)Optional接口,這增加了JIT編譯器/分析器的負擔,并因此誘使人們使用非預期的復合類型(例如Foo implements Bar, Optional<Bazz>) 。
而且, Optional現(xiàn)在是Java不可或缺的一部分,因此,可以使它與JDK本身一起有效發(fā)展,包括內聯(lián)類和其他即將推出的Java新功能。
可選與流
與Optional相反, java.util.stream.Stream和專用版本(例如IntStream )確實是接口。 為什么Stream不像Optional那樣具體地進行最后的上課?
好吧,Streams有一套完全不同的要求。 可以從Collection或數(shù)組中獲取Stream但是有很多更強大的獲取Stream 。 可以從文件,套接字,隨機生成器甚至從數(shù)據庫中的表獲取Stream 。 如果Stream被密封,將無法實現(xiàn)這些功能。
Speedment Stream是一個庫的示例,該庫允許從幾乎任何數(shù)據庫中獲取標準Java Streams。 在此處閱讀有關Speedment Stream的更多信息。
結論
Optional密封,有充分的理由。 Optional的內部實現(xiàn)尚不明確,但這是值得付出的代價,它具有更好的性能和更清晰的用戶代碼。
流是非密封接口,任何人都可以實現(xiàn),并可用于從各種來源(包括文件和數(shù)據庫表)獲取元素。 Speedment Stream ORM可用于從數(shù)據庫表中獲取Streams。
在此處下載Speedment Stream。
翻譯自: https://www.javacodegeeks.com/2019/08/java-optional-implementation-optional.html
總結
以上是生活随笔為你收集整理的Java:可选的可选实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全字少一横是什么字 全字少一横怎么读
- 下一篇: 东南风是从哪向哪吹的 哪边吹来的是东南风