在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

Java 8星期五:Java 8的阴暗面相关推荐

  1. Java 8中Lambda表达式的阴暗面

    这篇文章可能不会使我成为任何新朋友. 哦,好吧,无论如何我从来没有真正在学校受到欢迎. 但是,让我们说清楚. 就语言而言,Java 8的最大特色无疑是Lambda表达式. 几年来,它一直是功能语言(例 ...

  2. 【Java基础】· Java基本语法:程序流程控制习题总结

    写在前面 Hello大家好, 我是[麟-小白],一位软件工程专业的学生,喜好计算机知识.希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!! ...

  3. Java基础知识——Java语言基础

    ---------------------- ASP.Net+Android+IO开发S. .Net培训.期待与您交流! ---------------------- 2.Java语言基础 Java语 ...

  4. java 读取txt,java读取大文件

    java 读取txt,java读取大文件 package com.bbcmart.util; import java.io.File; import java.io.RandomAccessFile; ...

  5. JAVA基础(JAVA 执行环境) 第一天

    JAVA程序有3中执行环境. (1)能够单独运行的程序,称为Java Application(Java应用程序). (2)在Internet浏览器中运行的程序,称为 Java Applet(JAVA小 ...

  6. java.utilDate和java.sql.Date

    java.utilDate和java.sql.Date由广州疯狂软件教育java培训分享: java程序中的时间类型有java.util.Date和java.sql.Date两种.两者之间的关系和转化 ...

  7. java 终极超类,Java问答:终极父类(3),java问答

    Java问答:终极父类(3),java问答Java问答:终极父类(上) Java问答:终极父类(下) Java问答:终极父类(2)-上篇 Java问答:终极父类(2)-下篇 在之前关于 Object ...

  8. java.lang.OutOfMemoryError: Java heap space错误及...

    为什么80%的码农都做不了架构师?>>>    以下是从网上找到的关于堆空间溢出的错误解决办法: java.lang.OutOfMemoryError: Java heap spac ...

  9. 浅谈Java SE、Java EE、Java ME三者的区别

    1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程 ...

最新文章

  1. python函数的基础知识_Python入门基础知识点(函数进阶)
  2. 关于object references an unsaved transient instance - save the transient instance before flushing的解决方法
  3. POS消费机C#例子代码
  4. openCV中waitKey函数介绍
  5. 一台服务器装两个sql server_搭建我的世界基岩版服务器
  6. 怎样用python自动生成python代码_(Python)自动生成代码(方法一)
  7. HTML-a标签添加下划线
  8. 一年多开源没进展,我也放弃了
  9. 批处理对文件夹、所有子文件夹内的文件重命名、删除
  10. Ricequant米矿【MACD策略代码解释】量化交易
  11. 直连线和交叉线的区别
  12. 读文献——《Deep Residual Learning for Image Recognition》
  13. 父债子偿有法可依吗?可法院却对这个案子说:不!
  14. Mysql分页Limt
  15. 微软2007日语输入法
  16. 将100以内的所有质数输出
  17. ORAN专题系列-18:5G O-RAN FrontHaul前传接口互操作性测试规范IOT概述与总体架构
  18. [杂谈] 机器学习与优化算法的对比
  19. 超导体磁通穿透,交流损耗ANSYS仿真程序免费下载
  20. cdoj1339郭大侠与线上游戏

热门文章

  1. 第13步 用户模块前端(Admin)
  2. android 处理http状态码,OkHttp(Retrofit)对于http状态码202的处理
  3. org.springframework.uti包下的StringUtils的使用和org.apache.commons.lang包下StringUtils的使用
  4. fastdfs 集群 java_FastDFS集群部署(转载 写的比较好)
  5. 多个会话对表加表级读锁和表级写锁后的操作权限分析(表级读锁+表级写锁)
  6. 什么是通用字符名称?_通用名称
  7. 数据库班级字段怎么定义名称_班级名称
  8. jvm7 jvm8_JVM PermGen –您在哪里?
  9. jboss架构_检查Red Hat JBoss BRMS部署架构的规则和事件(第一部分)
  10. activemq网络桥接_ActiveMQ –经纪人网络解释–第4部分