您会后悔对Lambdas应用重载!

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

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

之前,在我们的文章: 如何设计良好的常规API中,我们已经就此主题进行过博客讨论。 今天,我们将研究如何…

Java 8更改规则

ryNBGfQ

是!

重载是一个很好的工具,可以在两个方面提供便利:

  • 通过提供参数类型替代
  • 通过提供参数默认值

来自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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 匿名对象有引用,封闭对象的引用通过匿名类java进行转义

我在实践中阅读Java并发性,下面的例子来自于此.我的问题是这个参考逃脱是什么意思&#xff1f;会有什么问题&#xff1f; .这个引用是如何从doSomething(e)中逃脱的.public class ThisEscape {public ThisEscape(EventSource source) {source.registerListener(new EventListen…

7.25第一次组队赛

Problem A UVA 11877 The Coco-Cola Store 直接输出n/2 1 #include <stdio.h>2 int main()3 {4 int n;5 while(~scanf("%d",&n) && n)6 {7 printf("%d\n",n/2);8 }9 return 0; 10 } 也可以模拟 1 #include <stdio.h>2 int main()…

如何:优化Hive ZooKeeper Lock Manager实施

Hive一直使用ZooKeeper作为分布式锁定管理器来支持HiveServer2中的并发。 基于ZooKeeper的锁管理器在小型环境中运行良好。 但是&#xff0c;随着越来越多的用户从HiveServer迁移到HiveServer2并开始创建大量并发会话&#xff0c;可能会出现问题。 主要问题是Hiveserver2和ZooK…

java 类之间转换,java中类对象之间的类型转换

类似于基本数据类型之间的强制类型转换。存在继承关系的父类对象和子类对象之间也可以在一定条件之下相互转换。这种转换需要遵守以下原则&#xff1a;1.子类对象可以被视为是其父类的一个对象2.父类对象不能被当作是某一个子类的对象。3.如果一个方法的形式参数定义的是父类对…

重载和重写以及重写的权限问题

简单说重载是发生在一个类中 重写是发生在子父类中的继承情况中 重载Overloading 方法重载是让类以统一的方式处理不同类型数据的一种手段。具有同名函数同时存在&#xff0c;具有不同参数类型/个数。重载overloading是一个类中多态兴的一种表现。 java的方法重载&#xff0c;就…

《图解HTTP》第1章 了解Web及网络基础

《图解HTTP》第1章 了解Web及网络基础 1. 使用 HTTP 协议访问 Web1.1 网络基础 TCP/IP1.2 TCP/IP 协议族1.2.1 TCP/IP 的分层管理 1. 使用 HTTP 协议访问 Web Web 使用一种名为 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09; 的协议作为…

JBoss Forge NetBeans集成–入门

JBoss Forge是构建基于Maven的Java EE项目的最快方法。 因此&#xff0c;它已经具有了令人敬畏的功能&#xff0c;使您作为开发人员的生活更加轻松。 在大多数情况下&#xff0c;使用Forge的人们可能会对创建Web应用程序感兴趣。 有很多入门Forge基础的方法。 您可以查看quick…

java版本的getorcreate,getOrCreate for java-rest-api neo4j失敗

我有一個簡單的關係測試&#xff0c;我試圖運行使用Rest API創建一個獨特的節點(java-rest-binding)https://github.com/neo4j/java-rest-binding但不幸的是我被困在某些東西上&#xff0c;這裏是細節&#xff1a;(非唯一的節點和關係工作完全正常&#xff0c;與這一點&#xf…

Nifty JUnit:在方法和类级别上使用规则

如Nifty JUnit&#xff1a;使用临时文件一文中所示 &#xff0c;可以在JUnit测试中使用Rule &#xff0c;这是方法级别的规则。 在此示例中&#xff0c;我想显示ClassRule用于类级别规则的变体。 方法规则 Rule在测试类的每个测试方法&#xff08;就像Before &#xff09;之前…

SQL语法的重要知识点总结

好几年没写SQL语句了。现在到了新的team&#xff0c;需要用到数据库。作为QA的话时常需要使用客户端工具连接到数据库中找寻或修改数据。这么长时间没使用&#xff0c;一些SQL的使用技巧都忘得差不多了。晚上看了一些资料&#xff0c;花了1个多小时又捡起了曾经的知识。现在总结…

java语法定制混淆,由撇号混淆的textpad语法高亮显示

我想知道在textpad的语法文件中放置什么来修复问题&#xff0c;例如&#xff0c;在html文件中&#xff0c;你正在写一个段落&#xff0c;而撇号会创建语法高亮&#xff0c;直到下一个aspostrophe .例如&#xff1a;Hi, I m an example.lol text here placeholder lorem ipsum I…

您需要了解的有关默认方法的所有信息

因此&#xff0c;默认方法是……昨天的新闻&#xff0c;对不对&#xff1f; 是的&#xff0c;但是使用一年后&#xff0c;积累了很多事实&#xff0c;我想将这些事实收集在一个地方&#xff0c;供刚开始使用它们的开发人员使用。 甚至有经验的人都可以找到他们不知道的一两个细…

RAC+ASM在单机上恢复的过程

IT168技术文档】网上也有类似的例子&#xff0c;但不尽详细&#xff0c;也没多花心思解释流程及原因&#xff0c;可能对初试者不太解惑。有感于此&#xff0c;故认真整理了恢复步骤即操作流程&#xff0c;望有助于同行朋友。 环境&#xff1a;正式环境是IBM4IBM5(RAC)&#xf…

php event_base_new,php event拓展基本使用

php event拓展基本使用2019-02-04 22:02:28(527)1. 确定io复用类型(select/poll/epoll)php$cfg new EventConfig();$cfg->avoidMethod("select");$cfg->avoidMethod("epoll");$base new EventBase($cfg);$sig Event::signal($base, SIGTERM, func…

OSGi服务测试助手:ServiceRegistrationRule

OSGi服务测试可以有效避免与悬挂的服务引用有关的问题。 就像我在写简单服务贡献验证中所承诺的那样&#xff0c;这次我引入了一个JUnit规则 &#xff0c;该规则有助于测试组件之间的交互。 OSGi服务测试组件交互 假设我们有一个服务&#xff0c;该服务通知根据whiteboard-pat…

php 在函数里打开链接,JavaScript中打开链接的几种方法介绍

如何使用JavaScript打开链接&#xff1f;本篇文章我们就来看看使用JavaScript打开链接的几种方法介绍。我们先来看一段代码使用Javascript实现打开链接&#xff0c;需要在location.href中替换要打开的链接的URL。location.href http://www.php.cn/blog.html;通过上述代码我们可…

三代基因组测序技术原理简介

考虑到cnblog不适合基因组领域这种类型的文章&#xff0c; 最终&#xff0c;我自己开通了公众号&#xff1a;碱基矿工&#xff0c;欢迎感兴趣的同学关注&#xff01; 也可以关注我的知乎&#xff1a;https://www.zhihu.com/people/yellowtree/activities 2018年1月修改&#x…

Java并发教程–锁定:显式锁定

1.简介 在许多情况下&#xff0c;使用隐式锁定就足够了。 有时&#xff0c;我们将需要更复杂的功能。 在这种情况下&#xff0c; java.util.concurrent.locks包为我们提供了锁定对象。 当涉及到内存同步时&#xff0c;这些锁的内部机制与隐式锁相同。 区别在于显式锁提供了其他…

POJ 1422 Air Raid (最小路径覆盖)

题意 给定一个有向图&#xff0c;在这个图上的某些点上放伞兵&#xff0c;可以使伞兵可以走到图上所有的点。且每个点只被一个伞兵走一次。问至少放多少伞兵。 思路 裸的最小路径覆盖。 最小路径覆盖 【路径覆盖】在一个有向图G(V, E<u,v>)中&#xff0c;路径覆盖就是在图…

自编码网络粒子群matlab,粒子群算法优化BP

这是数据1999 1611 1746 1277 753 323 229 7.10561325 1064 1414 1026 430 191 153 24.54521125 839 1197 857 301 168 139 …