c++ lambda 重载_您会后悔对Lambdas应用重载!
c++ lambda 重載
編寫(xiě)好的API很難。 非常辛苦。 如果您希望用戶喜歡您的API,則必須考慮很多事情。 您必須在以下兩者之間找到適當(dāng)?shù)钠胶?#xff1a;
之前,在我們的文章: 如何設(shè)計(jì)良好的常規(guī)API中,我們已經(jīng)就此主題進(jìn)行過(guò)博客討論。 今天,我們將研究如何…
Java 8更改規(guī)則
是!
重載是在兩個(gè)方面提供便利的好工具:
- 通過(guò)提供參數(shù)類型替代
- 通過(guò)提供參數(shù)默認(rèn)值
來(lái)自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 ,我們甚至可能會(huì)濫用一點(diǎn):
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之類的語(yǔ)言通過(guò)聲稱以上內(nèi)容是在Java中使用重載的唯一合理原因,將便利性這一概念進(jìn)一步提高了。 因此,錫蘭(Ceylon)的創(chuàng)建者已完全消除了其語(yǔ)言中的重載,將以上內(nèi)容替換為聯(lián)合類型和參數(shù)的實(shí)際默認(rèn)值。 例如
// Union types void sort(int[]|long[] a) { ... }// Default argument values IntStream stream(int[] array,int startInclusive = 0,int endInclusive = array.length) { ... }閱讀“我希望在Java中擁有的十大錫蘭語(yǔ)言功能” ,以獲取有關(guān)錫蘭的更多信息。
不幸的是,在Java中,我們不能使用聯(lián)合類型或參數(shù)默認(rèn)值。 因此,我們必須使用重載為API使用者提供便捷的方法。
但是,如果您的方法參數(shù)是一個(gè)函數(shù)接口 ,則在方法重載方面,Java 7和Java 8之間的情況發(fā)生了巨大變化。 JavaFX在此給出一個(gè)示例。
JavaFX的“不友好”的ObservableList
JavaFX通過(guò)使它們“可觀察”來(lái)增強(qiáng)JDK集合類型。 不要與Observable混淆, Observable是JDK 1.0和Swing之前的恐龍類型。
JavaFX自己的Observable本質(zhì)上是這樣的:
public interface Observable {void addListener(InvalidationListener listener);void removeListener(InvalidationListener listener); }幸運(yùn)的是,這個(gè)InvalidationListener是一個(gè)功能接口:
@FunctionalInterface public interface InvalidationListener {void invalidated(Observable observable); }這很棒,因?yàn)槲覀兛梢宰鲆韵率虑?#xff1a;
Observable awesome = FXCollections.observableArrayList(); awesome.addListener(fantastic -> splendid.cheer());(請(qǐng)注意,我是如何用更開(kāi)朗的術(shù)語(yǔ)替換foo / bar / baz的。我們都應(yīng)該這樣做。Foo和bar是如此1970 )
不幸的是,當(dāng)我們做我們可能要做的事情時(shí),事情變得更加繁瑣。 即,與其聲明一個(gè)Observable , Observable是一個(gè)更加有用的ObservableList :
ObservableList<String> awesome = FXCollections.observableArrayList(); awesome.addListener(fantastic -> splendid.cheer());但是現(xiàn)在,我們?cè)诘诙惺盏骄幾g錯(cuò)誤:
awesome.addListener(fantastic -> splendid.cheer()); // ^^^^^^^^^^^ // The method addListener(ListChangeListener<? super String>) // is ambiguous for the type ObservableList<String>因?yàn)?#xff0c;本質(zhì)上...
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之前,這兩種偵聽(tīng)器類型是完全可區(qū)分的,并且仍然是可區(qū)分的。 您可以通過(guò)傳遞命名類型來(lái)輕松調(diào)用它們。 如果我們編寫(xiě)以下代碼,我們的原始代碼仍然可以使用:
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());所有這些措施將消除歧義。 但坦率地說(shuō),如果您必須顯式鍵入lambda或參數(shù)類型,則lambda的性能只有后者的一半。 我們擁有現(xiàn)代化的IDE,它們可以執(zhí)行自動(dòng)補(bǔ)全并幫助推斷類型,就像編譯器本身一樣。
想象一下,如果我們真的想調(diào)用另一個(gè)addListener()方法,它需要一個(gè)ListChangeListener。 我們必須寫(xiě)任何
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設(shè)計(jì)很難。 以前很難,現(xiàn)在變得越來(lái)越難。 在Java 8中,如果您的API方法的任何參數(shù)是功能接口,請(qǐng)三思而后行重載該API方法。 一旦您確定要繼續(xù)進(jìn)行重載,請(qǐng)?jiān)俅慰紤],這是否真的是一個(gè)好主意。
不服氣嗎? 仔細(xì)看一下JDK。 例如java.util.stream.Stream類型。 您看到多少個(gè)具有相同數(shù)量的功能接口參數(shù)的重載方法,而這些接口又采用了相同數(shù)量的方法參數(shù)(就像我們前面的addListener()示例中一樣)?
零。
在重載參數(shù)編號(hào)不同的地方有重載。 例如:
<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);調(diào)用collect()時(shí),您永遠(yuǎn)不會(huì)有任何歧義。
但是,如果參數(shù)編號(hào)沒(méi)有不同,并且參數(shù)本身的方法參數(shù)編號(hào)也沒(méi)有變化,則方法名稱也不同。 例如:
<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);現(xiàn)在,這在呼叫站點(diǎn)上非常令人討厭,因?yàn)槟仨氼A(yù)先考慮必須根據(jù)各種相關(guān)類型使用哪種方法。
但這確實(shí)是解決這一難題的唯一方法。 因此,請(qǐng)記住: 您會(huì)為L(zhǎng)ambdas應(yīng)用重載感到遺憾!
翻譯自: https://www.javacodegeeks.com/2015/02/you-will-regret-applying-overloading-with-lambdas.html
c++ lambda 重載
總結(jié)
以上是生活随笔為你收集整理的c++ lambda 重载_您会后悔对Lambdas应用重载!的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 备案域名市场分析(备案域名市场)
- 下一篇: 安卓软件大师下载安装(安卓软件大师)