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