c++ lambda 重载

编写好的API很难。 非常辛苦。 如果您希望用户喜欢您的API,则必须考虑很多事情。 您必须在以下两者之间找到适当的平衡:

  1. 用处
  2. 易用性
  3. 向后兼容
  4. 前向兼容性

之前,在我们的文章: 如何设计良好的常规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 )

不幸的是,当我们做我们可能要做的事情时,事情变得更加繁琐。 即,与其声明一个ObservableObservable是一个更加有用的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应用重载!相关推荐

  1. 您会后悔对Lambdas应用重载!

    编写好的API很难. 非常辛苦. 如果您想让用户喜欢您的API,则必须考虑很多事情. 您必须在以下两者之间找到适当的平衡: 有用性 易用性 向后兼容 前向兼容性 之前,在我们的文章: 如何设计良好的常 ...

  2. python 运算符重载_零基础小白Python入门必看:面向对象之典型魔术方法

    魔术方法 查看类的魔术方法 class A: passdir(A) # 可以得到类所有公有成员复制代码 输出结果如下 ['__class__', '__delattr__', '__dict__', ...

  3. java运算符重载_为什么Java不支持运算符重载?

    Java不支持运算符重载 = 小白也能学编程 Java之所以不支持运算符重载,并不是如下原因: 会使JVM变得复杂.性能下降:君不见C++内置运算符重载的能力?C++的性能在任何时代秒杀Java相信没 ...

  4. JAVA入门_继承与重载_饲养员喂养动物

    JAVA入门_继承与重载_饲养员喂养动物 实验要求 Tiger类 Feeder类 MainClass 运行结果 实验要求 本实验要求:本实验以饲养员喂养老虎为业务背景,体验"函数重载&quo ...

  5. java 漂亮的连接曲线_猜猜 Java 为什么不支持运算符重载?

    作者 | Yujiaao 来源 | https://segmentfault.com/a/1190000019962661 另一个类似的 Java 面试难题.为什么 C++ 支持运算符重载而 Java ...

  6. lambda 使用_如何使用Lambda和API网关构建API

    lambda 使用 Do you want to access your database, control your system, or execute some code from anothe ...

  7. C++_类和对象_C++运算符重载_函数调用运算符重载_---C++语言工作笔记060

    然后我们再来看函数调用运算符重载, 其实这个,重载后的,函数调用运算符有点像,仿函数,什么是仿函数,一会我们再说 我们去写一个MyPrint类 里面重载函数调用运算符,可以看到函数调用运算符的重载的写 ...

  8. C++_类和对象_C++运算符重载_加号运算符重载_实现两个对象相加_对象和int类型相加_通过成员函数重载+号_全局函数重载+号_以及重载_运算符重载函数实现---C++语言工作笔记055

    然后我们再来看,运算符的重载,首先我们来看加号的运算符的重载. 这个的作用是很明显的,比如我们有两个Person对象,p1,p2,如果我们想 p3 = p1+p2能可以嘛,不可以对吧,因为系统给我们提 ...

  9. c++重载运算符_C/C++编程笔记:运算符重载丨重载C++中的New和Delete运算符

    new和delete运算符也可以像C ++中的其他运算符一样重载.New和Delete运算符可以全局重载,也可以在特定类中重载. (1)如果使用某个类的成员函数来重载这些运算符,则意味着这些运算符仅针 ...

最新文章

  1. 【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )
  2. 【Flutter】Flutter 页面生命周期 ( 初始化期 | createState | initState | 更新期 | build | 销毁期 | dispose)
  3. Hadoop_NameNode_代码分析_目录树(2)
  4. Airflow 中文文档:初始化数据库后端
  5. 标签页添加点击事件和拖拽事件
  6. 苹果手机收不到推送信息_[赞助信息]拜仁签约新赞助商 球员将被禁用苹果手机...
  7. 统计学习方法读书笔记11-决策树课后习题
  8. css flex 之 flex-grow | flex-direction
  9. 国家地区标准代码(国际域名缩写)
  10. 京东后台图片优化技巧
  11. import * as用法
  12. win7电脑怎么伪装ip地址【系统天地】
  13. 如何用Python挖掘“啤酒和尿布”的关系?(Apriori算法挖掘关联规则)
  14. 测试项目启动与研读需求文档
  15. Java培训出来什么水平?
  16. 什么是绩效管理?企业如何做好绩效管理
  17. 考试酷c语言程序设计的答案大全,FX-TRN-BEG-C 考试酷 V-MECA组合在PLC项目教学中的运用...
  18. Flutter 开关和切换高级指南
  19. TextView使用textApperance属性设置字体颜色失效
  20. 看财报:新东方步入中老年

热门文章

  1. P1337-[JSOI2004]平衡点/吊打XXX【模拟退火】
  2. 2021牛客暑期多校训练营7 K-xay loves sequence(主席树+二分)
  3. 2021“MINIEYE杯”中国大学生算法设计超级联赛(2)I love counting(Trie树)
  4. bzoj 2908. 又是nand(树链剖分+区间NAND+单点修改)
  5. 纪中C组模拟赛总结(2019.7.8)
  6. 【离散化】【差分】幻灯片(jzoj 1609)
  7. 2017 ACM Jordanian Collegiate J.Efficiency Test 动态规划、类倍增
  8. L3-002 堆栈 树状数组+二分答案
  9. Mybatis简介与原理
  10. art-template入门(九)之API