Java 8星期五:Java 8的阴暗面

在Data Geekery ,我们喜欢Java。 而且,由于我们真的很喜欢jOOQ的流畅的API和查询DSL ,我们对Java 8将为我们的生态系统带来什么感到非常兴奋。

Java 8星期五

每个星期五,我们都会向您展示一些不错的教程风格的Java 8新功能,这些功能利用了lambda表达式,扩展方法和其他好东西。 您可以在GitHub上找到源代码 。

Java 8的阴暗面

到目前为止,我们已经展示了该新主要版本中令人激动的部分 。 但是也有一些警告。 其中很多。 那件事

  • ……令人困惑
  • … 错了
  • …被省略(目前)
  • …被省略(很长时间)

Java主要发行版总是有两个方面。 从好的方面来说,我们获得了许多新功能,大多数人会认为这是过期的 。 其他语言,平台早在Java 5之前就有泛型。其他语言,平台早在Java 8之前就有lambda。但是现在,我们终于有了这些功能。 在通常的古怪Java方式中。

Lambda表达式的引入非常优美。 从向后兼容的角度来看,能够将每个匿名SAM实例编写为lambda表达式的想法非常引人注目。 那么,什么黑暗面到Java 8?

超载变得更糟

重载,泛型和vararg不是朋友。 我们已经在上一篇文章以及这个Stack Overflow问题中 对此进行了解释 。 在您的奇怪应用程序中,这些可能并非每天都有问题,但对于API设计人员和维护人员而言,这是非常重要的问题。

使用lambda表达式,事情变得“更糟”。 因此,您认为可以提供一些便利的API,重载现有的run()方法(该方法接受Callable也接受新的Supplier类型:

static <T> T run(Callable<T> c) throws Exception {return c.call();
}static <T> T run(Supplier<T> s) throws Exception {return s.get();
}

看起来非常有用的Java 7代码现在是Java 8的一大难题。 因为您不能仅使用lambda参数简单地调用这些方法:

public static void main(String[] args)
throws Exception {run(() -> null);//  ^^^^^^^^^^ ambiguous method call
}

倒霉。 您将不得不采用以下任一“经典”解决方案:

run((Callable<Object>) (() -> null));run(new Callable<Object>() {@Overridepublic Object call() throws Exception {return null;}});

因此,尽管总有变通办法,但这些变通办法总是“糟透了”。 即使从向后兼容的角度来看事情不会中断,这也真是令人沮丧。

并非所有关键字都支持默认方法

默认方法是一个不错的补充。 有人可能声称Java最终具有特质 。 其他人显然与该术语脱离了关系,例如Br​​ian Goetz:

向Java添加默认方法的主要目标是“接口演变”,而不是“穷人的特征”。

如lambda-dev邮件列表中所示。

事实是,默认方法与Java中的其他任何东西相比都有很多正交和不规则的特征。 这里有一些批评:

他们不能成为最终的

鉴于默认方法也可以用作API中的便捷方法:

public interface NoTrait {// Run the Runnable exactly oncedefault final void run(Runnable r) {//  ^^^^^ modifier final not allowedrun(r, 1);}// Run the Runnable "times" timesdefault void run(Runnable r, int times) {for (int i = 0; i < times; i++)r.run();}
}

不幸的是,以上操作是不可能的,因此第一个重载的便捷方法可能会在子类型中被覆盖,即使这对API设计人员而言毫无意义。

无法使其同步

mm! 用语言难以实现吗?

public interface NoTrait {default synchronized void noSynchronized() {//  ^^^^^^^^^^^^ modifier synchronized//  not allowedSystem.out.println("noSynchronized");}
}

是的, synchronized很少使用,就像决赛。 但是,当您有了用例时,为什么不仅仅允许它呢? 是什么使接口方法主体如此特别?

默认关键字

这也许是所有功能中最怪异和最不规则的。 default关键字本身。 让我们比较一下接口和抽象类:

// Interfaces are always abstract
public /* abstract */ interface NoTrait {// Abstract methods have no bodies// The abstract keyword is optional/* abstract */ void run1();// Concrete methods have bodies// The default keyword is mandatorydefault void run2() {}
}// Classes can optionally be abstract
public abstract class NoInterface {// Abstract methods have no bodies// The abstract keyword is mandatoryabstract void run1();// Concrete methods have bodies// The default keyword mustn't be usedvoid run2() {}
}

如果从头开始重新设计该语言,则可能不需要任何abstractdefault关键字。 两者都是不必要的。 存在或不存在主体的事实足以使编译器评估方法是否抽象。 即,情况应该如何:

public interface NoTrait {void run1();void run2() {}
}public abstract class NoInterface {void run1();void run2() {}
}

上面会更精简和更常规。 遗憾的是,EG从未真正讨论过default的用途。 好吧,这是经过辩论的,但是EG从来不想接受这种选择。 我已经尝试过运气,下面的响应 :

我不认为#3是一种选择,因为与方法主体的接口一开始是不自然的。 至少指定“默认”关键字为读者提供了某种语言来说明语言允许方法主体的原因。 就个人而言,我希望接口将保持纯合同形式(不执行),但是我不知道有更好的选择来发展接口。

同样,这是EG的明确承诺,即不承诺Java中的“特征”。 默认方法是实现1-2个其他功能的纯粹必要手段。 他们从一开始就没有精心设计。

其他修饰符

幸运的是,在项目后期,使用了static修饰符使其成为了规范。 因此现在可以在接口中指定静态方法。 但是由于某种原因,这些方法不需要(也不允许!) default关键字,它必须是EG完全随机决定的,就像您显然无法在接口中定义static final方法一样。

虽然可见性修饰符已在lambda-dev邮件列表中进行了讨论 ,但超出了此版本的范围。 也许,我们可以在将来的版本中获得它们。

实际上很少执行默认方法

有些方法在接口上会有合理的默认实现–可能会猜测。 直观地,像ListSet这样的collections接口会将它们放在其equals()hashCode()方法上,因为这些方法的协定在接口上定义良好。 它还使用listIterator()AbstractList实现,对于大多数定制列表而言,这是合理的默认实现。

如果对这些API进行改造,以使使用Java 8更加容易实现自定义集合,那就太好了。例如,我可以使我的所有业务对象都实现List ,而不会浪费AbstractList上的单个基类继承。

但是,可能有一个与向后兼容性相关的令人信服的原因阻止了Oracle的Java 8团队实现这些默认方法。 凡是向我们发送此原因的人都将获得免费的jOOQ标签 !

不是在这里发明的-心态

在lambda-dev EG邮件列表中也多次批评了这一点。 而且在撰写本博客系列文章时 ,我只能确认新的功能接口让人很难记住。 由于这些原因,他们感到困惑:

一些原始类型比其他更平等

与所有其他类型相比, intlongdouble基本类型是首选的,因为它们在java.util.function包以及整个Streams API中都具有功能接口。 boolean是二等公民,因为它仍然把它做成包在一个形式BooleanSupplierPredicate ,或者更糟: IntPredicate

所有其他原始类型在该区域中实际上并不存在。 即没有针对byteshortfloatchar特殊类型。 尽管满足最后期限的争论无疑是有效的,但这种古怪的现状将使新手很难学习这种语言。

类型不仅仅称为函数

坦白说吧。 所有这些类型都只是“功能”。 没有人真正关心ConsumerPredicateUnaryOperator等之间的隐式差异。

实际上,当您寻找具有非void返回值和两个参数的类型时,您可能会调用什么呢? Function2 ? 好吧,你错了。 它称为BiFunction

这是一个决策树,用于了解您要查找的类型如何被调用:

  • 您的函数返回void吗? 叫做Consumer
  • 您的函数返回boolean吗? 这叫做Predicate
  • 您的函数返回intlongdouble吗? 它叫做XXToIntYYXXToLongYYXXToDoubleYY东西
  • 您的函数没有参数吗? 叫做Supplier
  • 您的函数是否接受一个intlongdouble参数? 它称为IntXXLongXXDoubleXX东西
  • 您的函数有两个参数吗? 叫做BiXX
  • 您的函数是否接受两个相同类型的参数? 叫做BinaryOperator
  • 您的函数返回的类型是否与作为单个参数的类型相同? 叫做UnaryOperator
  • 您的函数是否接受两个参数,其中第一个是引用类型,第二个是原始类型? 它称为ObjXXConsumer (只有使用该配置的使用者存在)
  • 否则:称为Function

好主啊! 最近,我们当然应该去Oracle Education检查一下Oracle Certified Java Programmer课程的价格是否急剧上涨了……幸运的是,有了Lambda表达式,我们几乎不必记住所有这些类型!

有关Java 8的更多信息

Java 5泛型为Java语言带来了许多很棒的新功能。 但是也有很多与类型擦除有关的警告。 Java 8的默认方法,Streams API和lambda表达式将再次为Java语言和平台带来很多很棒的新功能。 但是我们确信, Stack Overflow很快就会因在Java 8丛林中迷路的困惑程序员而引发问题。

学习所有新功能并非易事,但是新功能(和警告)仍然存在。 如果您是Java开发人员,则最好在有机会的时候立即开始练习。 因为我们还有很长的路要走。

翻译自: https://www.javacodegeeks.com/2014/04/java-8-friday-the-dark-side-of-java-8.html

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

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

相关文章

SQL,HQL,CQL,JPQL了解

SQL&#xff08;Structured Query Language&#xff09; 是关系数据库查询语言。from后面跟的是“表名”&#xff0c;where后用“表中字段”做条件 HQL&#xff08;Hibernate Query Language&#xff09; 是面向对象的查询&#xff0c;from后面跟的是“表名”&#xff0c;where…

报错集锦

1.在node后端使用express中的multer中间件来实现文件上传时报错 node multer 报错Unexpected field 1 var expressrequire(express); 2 3 var routerexpress.Router(); 4 5 var uploadrequire(...) router.post(/upload,upload.single(fileid)); 原因&&解决&#xff…

shipyard-----------docker容器的可视化管理

shipyard是什么&#xff0c;由题目就可知&#xff0c;是一个对docker进行管理的可视化界面 照此步骤就能完成对shipyard搭建 <ip-of-host>内容要修改成你的docker0的IP地址&#xff0c;不知道的话就ifconfig就好了 如果搭建不成功则是防火墙未开放4001端口&#xff1a;su…

virtualbox怎么共享文件夹 linux,Virtualbox中Ubuntu设置共享文件夹

1、安装增强功能包(Guest Additions)VirtualBox中&#xff0c;选择”设备” -> “安装增强功能”。命令行输入&#xff1a;$ cd /media/VBoxGuestAdditions_4.3.8_RC1$ sudo ./VboxLinuxAdditions.run开始安装工具包&#xff0c;安装完毕后重启虚拟机。2、配置共享文件夹Vir…

Eclipse对Java(TM)8的官方支持

Java开发工具&#xff08;JDT&#xff09;项目的项目负责人Dani Megert今天早些时候宣布了此声明 &#xff1a; Eclipse顶级项目非常自豪地宣布正式支持Java™8。从I20140318-0830开始&#xff0c;所有的Luna&#xff08;4.4&#xff09;构建都包含Eclipse对Java™8的支持。对…

Quartz.net使用笔记

一、需求场景&#xff1a;每天固定时间执行某个行为/动作。 一开始想用定时器&#xff0c;后来无意间发现了这个插件&#xff0c;感觉功能太强大了&#xff0c;完美解决了我的问题。 二、下载地址&#xff1a;https://www.quartz-scheduler.net/ 也可以在项目中直接使用nugut进…

JS里面的懒加载(lazyload)

懒加载技术(简称lazyload)并不是新技术, 它是js程序员对网页性能优化的一种方案.lazyload的核心是按需加载 涉及到图片&#xff0c;falsh资源 , iframe, 网页编辑器(类似FCK)等占用较大带宽&#xff0c;且这些模块暂且不在浏览器可视区内,因此可以使用lazyload在适当的时候加载…

远程拷贝 linux服务器,linux scp 服务器远程拷贝(示例代码)

一、将本机文件复制到远程服务器上#scp /home/administrator/news.txt [email protected]:/etc/squid/home/administrator/ 本地文件的绝对路径news.txt 要复制到服务器上的本地文件root 通过root用户登录到远程…

对偶图小结

前提 通常对偶图建立在平面图之上 平面图&#xff1a;单边除端点外无交点 解决范围 求平面图的最大流 做法 平面图显然在边的基础上分成了若干个块&#xff0c;每个块由一个结点来维护 在边缘出与源点汇点联通&#xff0c;中间处结点之间相互联通 连的边容量为该边穿过原图的边…

将Java 8支持添加到Eclipse Kepler

是否想向开普勒添加Java 8支持&#xff1f; Java 8尚未加入我们的标准下载包中 。 但是您可以将其添加到现有的Eclipse Kepler软件包中。 我有运行Java 8的三种不同的Eclipse安装&#xff1a; 面向Java开发人员的Eclipse IDE的全新Kepler SR2安装&#xff1b; 为RCP / RAP开…

CSS基础【1】:体验CSS

CSS起源 web的衰落&#xff1a;在 web 早期&#xff08;1990-1993&#xff09;,html是一个很局限的语言。几乎完全由用于描述段落&#xff0c;超链接&#xff0c;列表和标题的结构化元素组成。随着万维网的出现&#xff08;用户交互体验的加强&#xff09;&#xff0c;对 html …

JS中的兼容问题总结

今天总结总结在JS里面遇到的兼容性问题 1.获取滚动距离的兼容性问题: document.documentElement.scrollTop || document.body.scrollTop &#xff08;兼容IE&#xff09; 2.获取非行间样式 getComputedStyle(元素,false)[attr] || 元素.currentStyle[attr] 3.索引…

linux网络唤醒,如何在Ubuntu Server 18.04中启用网络唤醒(WOL)

网络唤醒(WOL)是一种行业标准协议&#xff0c;用于远程唤醒服务器。如果您管理着很多设备&#xff0c;因此不需要为了唤醒服务器而去数据中心。启用允许您远程执行此操作的功能&#xff0c;这样您可以更高效地工作。Ubuntu 系统默认没有启用WOL&#xff0c;所以我们要设置它。我…

php 分页处理

1、利用bootstrap的css框架的前提下&#xff0c;封装个Php的分页框架 命名为test.php&#xff0c;具体代码如下 1 <?php2 class Pagination3 {4 private $cfg;5 private $content ; //分页导行条内容部份6 7 public function __constr…

ActiveMQ –经纪人网络解释

目的 这个由7部分组成的博客系列将分享有关如何创建ActiveMQ代理网络以实现高可用性和可伸缩性的信息。 为什么要建立经纪人网络&#xff1f; ActiveMQ消息代理是企业中消息传递基础结构的核心组件。 它需要高度可用并且可以动态伸缩&#xff0c;以促进具有不同容量需求的动态…

13 创建高级联结

13.1 使用表别名 在之前的例子中&#xff0c;我们用的都是用的列别名&#xff0c;SQL还允许给表名起别名。 13.2 使用不同类型的联结 我们在上一章使用的只是称为内部联结或等值联结&#xff08; equijoin&#xff09; 的简单联结&#xff0c;现在来看3种其他联结&#xff0c;…

JS中undefined和null的区别,以及出现原因

区别&#xff1a;null是一个表示无的对象&#xff0c;转换为数值为0&#xff1b; undefined表示一个无的原始值&#xff0c;转化为数值为NAN&#xff08;与任何数字相加也为NAN&#xff09; undefined出现原因&#xff1a;(口诀&#xff1a;一变量二函数一对象) 1.变量被声明了…

判断一个数是不是质数

number int(input("请输入数字&#xff1a;"))count 2while count < number -1: if number % count 0: #质数是除了1和它本身能除尽。将这个数从2开始除&#xff0c;除到number-1&#xff0c;如果有除尽的就不是质数&#xff0c;如果没有就是质数。…

Java 8:功能接口示例

为了支持Java 8中的lambda表达式&#xff0c;他们引入了Functional Interfaces。 具有单一抽象方法的接口可以称为功能接口。 Runnable&#xff0c;Comparator&#xff0c;Cloneable是功能接口的一些示例。 我们可以使用Lambda表达式实现这些功能接口。 例如&#xff1a; Th…

正则表达式验证问题(用户名、密码、email、身份证

实现的代码如下&#xff1a; 1 <html>2 <head>3 <meta charset"UTF-8">4 </head>5 <body>6 <p>用户名正则表达式 &#xff0c;4到16位&#xff08;字母&#xff0c;数字&#xff0c;下滑线&#xff0c;减号&#xff09;</p&g…