c++ lambda 重载_您会后悔对Lambdas应用重载!
c++ lambda 重載
編寫好的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
c++ lambda 重載
總結
以上是生活随笔為你收集整理的c++ lambda 重载_您会后悔对Lambdas应用重载!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 备案域名市场分析(备案域名市场)
- 下一篇: 安卓软件大师下载安装(安卓软件大师)