日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

您会后悔对Lambdas应用重载!

發布時間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 您会后悔对Lambdas应用重载! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

編寫好的API很難。 非常辛苦。 如果您想讓用戶喜歡您的API,則必須考慮很多事情。 您必須在以下兩者之間找到適當的平衡:

  • 有用性
  • 易用性
  • 向后兼容
  • 前向兼容性
  • 之前,在我們的文章: 如何設計良好的常規API中,我們已經就此主題進行過博客討論。 今天,我們將研究如何…

    Java 8更改規則

    是!

    重載是一個很好的工具,可以在兩個方面提供便利:

    • 通過提供參數類型替代
    • 通過提供參數默認值

    來自JDK的上述示例包括:

    public class Arrays {// Argument type alternativespublic static void sort(int[] a) { ... }public static void sort(long[] a) { ... }// Argument default valuespublic static IntStream stream(int[] array) { ... }public static IntStream stream(int[] array, int startInclusive, int endExclusive) { ... } }

    jOOQ API顯然充滿了這種便利。 由于jOOQ是SQL的DSL ,我們甚至可能會濫用一點:

    public interface DSLContext {<T1> SelectSelectStep<Record1<T1>> select(SelectField<T1> field1);<T1, T2> SelectSelectStep<Record2<T1, T2>> select(SelectField<T1> field1, SelectField<T2> field2);<T1, T2, T3> SelectSelectStep<Record3<T1, T2, T3>> sselect(SelectField<T1> field1, SelectField<T2> field2, SelectField<T3> field3);<T1, T2, T3, T4> SelectSelectStep<Record4<T1, T2, T3, T4>> select(SelectField<T1> field1, SelectField<T2> field2, SelectField<T3> field3, SelectField<T4> field4);// and so on... }

    諸如Ceylon之類的語言通過聲稱以上內容是在Java中使用重載的唯一合理原因,將便利性這一概念進一步提高了。 因此,錫蘭(Ceylon)的創建者已完全消除了其語言中的重載,將以上內容替換為聯合類型和參數的實際默認值。 例如

    // Union types void sort(int[]|long[] a) { ... }// Default argument values IntStream stream(int[] array,int startInclusive = 0,int endInclusive = array.length) { ... }

    閱讀“我希望我們在Java中擁有的十大錫蘭語言功能” ,以獲取有關錫蘭的更多信息。

    不幸的是,在Java中,我們不能使用聯合類型或參數默認值。 因此,我們必須使用重載為API使用者提供便捷的方法。

    但是,如果您的方法參數是一個函數接口 ,則在方法重載方面,Java 7和Java 8之間的情況發生了巨大變化。 JavaFX在此提供了一個示例。

    JavaFX的“不友好”的ObservableList

    JavaFX通過使它們“可觀察”來增強JDK集合類型。 不要與Observable混淆, Observable是JDK 1.0和Swing之前的恐龍類型。

    JavaFX自己的Observable本質上是這樣的:

    public interface Observable {void addListener(InvalidationListener listener);void removeListener(InvalidationListener listener); }

    幸運的是,這個InvalidationListener是一個功能接口:

    @FunctionalInterface public interface InvalidationListener {void invalidated(Observable observable); }

    這很棒,因為我們可以做以下事情:

    Observable awesome = FXCollections.observableArrayList(); awesome.addListener(fantastic -> splendid.cheer());

    (請注意,我是如何用更愉快的術語替換foo / bar / baz的。我們都應該這樣做。Foo和bar是如此1970 )

    不幸的是,當我們做我們可能要做的事情時,事情變得更加繁瑣。 也就是說,與其聲明一個Observable , Observable是一個更加有用的ObservableList :

    ObservableList<String> awesome = FXCollections.observableArrayList(); awesome.addListener(fantastic -> splendid.cheer());

    但是現在,我們在第二行收到編譯錯誤:

    awesome.addListener(fantastic -> splendid.cheer()); // ^^^^^^^^^^^ // The method addListener(ListChangeListener<? super String>) // is ambiguous for the type ObservableList<String>

    因為,本質上...

    public interface ObservableList<E> extends List<E>, Observable {void addListener(ListChangeListener<? super E> listener); }

    和…

    @FunctionalInterface public interface ListChangeListener<E> {void onChanged(Change<? extends E> c); }

    再一次,在Java 8之前,這兩種偵聽器類型是完全可區分的,并且仍然是。 您可以通過傳遞命名類型來輕松調用它們。 如果我們編寫以下代碼,我們的原始代碼仍然可以使用:

    ObservableList<String> awesome = FXCollections.observableArrayList(); InvalidationListener hearYe = fantastic -> splendid.cheer(); awesome.addListener(hearYe);

    要么…

    ObservableList<String> awesome = FXCollections.observableArrayList(); awesome.addListener((InvalidationListener) fantastic -> splendid.cheer());

    甚至…

    ObservableList<String> awesome = FXCollections.observableArrayList(); awesome.addListener((Observable fantastic) -> splendid.cheer());

    所有這些措施將消除歧義。 但坦率地說,如果您必須顯式鍵入lambda或參數類型,則lambda的性能只有后者的一半。 我們擁有現代化的IDE,它們可以執行自動補全并幫助推斷類型,就像編譯器本身一樣。

    想象一下,如果我們真的想調用另一個addListener()方法,它需要一個ListChangeListener。 我們必須寫任何

    ObservableList<String> awesome = FXCollections.observableArrayList();// Agh. Remember that we have to repeat "String" here ListChangeListener<String> hearYe = fantastic -> splendid.cheer(); awesome.addListener(hearYe);

    要么…

    ObservableList<String> awesome = FXCollections.observableArrayList();// Agh. Remember that we have to repeat "String" here awesome.addListener((ListChangeListener<String>) fantastic -> splendid.cheer());

    甚至…

    ObservableList<String> awesome = FXCollections.observableArrayList();// WTF... "extends" String?? But that's what this thing needs... awesome.addListener((Change<? extends String> fantastic) -> splendid.cheer());

    必須警惕。

    API設計很難。 以前很難,現在變得越來越難。 在Java 8中,如果您的API方法的任何參數是功能接口,請三思而后行重載該API方法。 一旦您確定要繼續進行重載,請再次思考,這是否真的是一個好主意。

    不服氣嗎? 仔細看一下JDK。 例如java.util.stream.Stream類型。 您看到多少個具有相同數量的功能接口參數的重載方法,而這些接口又使用了相同數量的方法參數(就像我們前面的addListener()示例中一樣)?

    零。

    在重載參數編號不同的地方有重載。 例如:

    <R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);<R, A> R collect(Collector<? super T, A, R> collector);

    調用collect()時,您永遠不會有任何歧義。

    但是,如果參數編號沒有不同,并且參數本身的方法參數編號也沒有變化,則方法名稱也不同。 例如:

    <R> Stream<R> map(Function<? super T, ? extends R> mapper); IntStream mapToInt(ToIntFunction<? super T> mapper); LongStream mapToLong(ToLongFunction<? super T> mapper); DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);

    現在,這在呼叫站點上非常令人討厭,因為您必須事先考慮必須根據各種相關類型使用哪種方法。

    但這確實是解決這一難題的唯一方法。 因此,請記住: 您會為Lambdas應用重載感到遺憾!

    翻譯自: https://www.javacodegeeks.com/2015/02/you-will-regret-applying-overloading-with-lambdas.html

    總結

    以上是生活随笔為你收集整理的您会后悔对Lambdas应用重载!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。