芜湖龙湖建设工程有限公司网站,花生壳建设网站,北京 营销型网站,不用下载就能玩的网页游戏在Data Geekery #xff0c;我们喜欢Java。 而且#xff0c;由于我们真的很喜欢jOOQ的流畅的API和查询DSL #xff0c;我们对Java 8将为我们的生态系统带来什么感到非常兴奋。 Java 8星期五 每个星期五#xff0c;我们都会向您展示一些不错的教程风格的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(CallableT c) throws Exception {return c.call();
}static T T run(SupplierT 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((CallableObject) (() - null));run(new CallableObject() {Overridepublic Object call() throws Exception {return null;}}); 因此尽管总有变通办法但这些变通办法总是“糟透了”。 即使从向后兼容的角度来看事情不会中断这也真是令人沮丧。 并非所有关键字都支持默认方法 默认方法是一个不错的补充。 有人可能声称Java最终具有特质 。 其他人显然与该术语脱离了关系例如Brian 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 mustnt be usedvoid run2() {}
} 如果从头开始重新设计该语言则可能不需要任何abstract或default关键字。 两者都是不必要的。 存在或不存在主体的事实足以使编译器评估方法是否抽象。 即情况应该如何 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邮件列表中进行了讨论 但超出了此版本的范围。 也许我们可以在将来的版本中获得它们。 实际上很少执行默认方法 有些方法在接口上会有合理的默认实现–可能会猜测。 直观地像List或Set这样的collections接口会将它们放在其equals()和hashCode()方法上因为这些方法的协定在接口上定义良好。 它还使用listIterator()在AbstractList实现对于大多数定制列表而言这是合理的默认实现。 如果对这些API进行改造以使使用Java 8更加容易实现自定义集合那就太好了。例如我可以使我的所有业务对象都实现List 而不会浪费AbstractList上的单个基类继承。 但是可能有一个与向后兼容性相关的令人信服的原因阻止了Oracle的Java 8团队实现这些默认方法。 凡是向我们发送此原因的人都将获得免费的jOOQ标签 不是在这里发明的-心态 在lambda-dev EG邮件列表中也多次批评了这一点。 而且在撰写本博客系列文章时 我只能确认新的功能接口让人很难记住。 由于这些原因他们感到困惑 一些原始类型比其他更平等 与所有其他类型相比 int long double基本类型是首选的因为它们在java.util.function包以及整个Streams API中都具有功能接口。 boolean是二等公民因为它仍然把它做成包在一个形式BooleanSupplier或Predicate 或者更糟 IntPredicate 。 所有其他原始类型在该区域中实际上并不存在。 即没有针对byte short float和char特殊类型。 尽管满足最后期限的争论无疑是有效的但这种古怪的现状将使新手很难学习这种语言。 类型不仅仅称为函数 坦白说吧。 所有这些类型都只是“功能”。 没有人真正关心Consumer Predicate UnaryOperator等之间的隐式差异。 实际上当您寻找具有非void返回值和两个参数的类型时您可能会调用什么呢 Function2 好吧你错了。 它称为BiFunction 。 这是一个决策树用于了解您要查找的类型如何被调用 您的函数返回void吗 叫做Consumer 您的函数返回boolean吗 这叫做Predicate 您的函数返回int long double吗 它叫做XXToIntYY XXToLongYY XXToDoubleYY东西 您的函数没有参数吗 叫做Supplier 您的函数是否接受一个int long double参数 它称为IntXX LongXX DoubleXX东西 您的函数有两个参数吗 叫做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