默认方法:Java 8的无名英雄

几周前,我写了一个博客,说开发人员学习新语言是因为它们很酷。 我仍然坚持这个主张,因为关于Java 8的事情真的很酷。 毫无疑问,该节目的明星是添加了Lambdas以及将函数提升为一等变量,而我目前最喜欢的是默认方法。 这是因为它们是在不破坏旧代码的情况下向现有接口添加新功能的一种巧妙方法。

实现很简单:采用一个接口,添加一个具体方法,并将关键字default附加为修饰符。 结果是,接口的所有现有实现突然都可以使用此代码。 在第一个简单示例中,我添加了默认方法,该方法返回接口1的版本号。

public interface Version { /** * Normal method - any old interface method: * * @return Return the implementing class's version */ public String version(); /** * Default method example. * * @return Return the version of this interface */ default String interfaceVersion() { return "1.0"; } }

然后,您可以在任何实现类上调用此方法。

public class VersionImpl implements Version { @Override public String version() { return "My Version Impl"; } 
}

您可能会问:为什么这很酷? 如果采用java.lang.Iterable接口并添加以下默认方法,则会使for循环失效。

default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }

forEach方法采用实现Consumer<T>接口作为参数的类的实例。 Consumer<T>可以在新的java.util.function包中找到,它是Java 8所谓的功能接口 ,该接口仅包含一个方法。 在这种情况下,方法accept(T t)接受一个参数并且返回一个void

java.util.function软件包可能是Java 8中最重要的软件包之一。它包含一堆描述通用函数类型的单一方法或函数接口。 例如, Consumer<T>包含一个接受一个参数并返回void的函数,而Predicate<T>是一个包含一个接受一个参数并返回boolean的函数的接口,通常用于编写过滤lambda。

该接口的实现应包含您先前在for循环括号之间编写的内容。

那么,您可能会想,这给了我什么? 如果不是Java 8,那么答案是“不多”。 要在Java 8之前使用forEach(…)方法,您需要编写如下代码:

List<String> list = Arrays.asList(new String[] { "A", "FirsT", "DefaulT", "LisT" }); System.out.println("Java 6 version - anonymous class"); Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String t) { System.out.println(t); } }; list.forEach(consumer);

但是,如果将其与lambda表达式或方法引用结合使用,则可以编写一些看起来很酷的代码。 使用方法引用,前面的示例变为:

list.forEach(System.out::println);

您可以使用lambda表达式执行相同的操作:

list.forEach((t) -> System.out.println(t));

所有这些似乎都与Java 8背后的一个重要思想保持一致:让JDK为您完成工作。 用政治家和连环友约翰·肯尼迪(John F Kennedy)的话来形容“不要问您对JDK可以做什么,请问您的JDK可以为您做什么” 2

默认方法的设计问题

那是编写无处不在的for循环的一种很酷的新方法,但是在接口中添加默认方法是否存在问题?如果是的话,它们是什么?Java 8项目中的人如何修复它们?

首先要考虑的是继承。 当您拥有一个扩展了另一个接口的接口并且两个接口都具有带有相同签名的默认方法时,会发生什么? 例如,如果您拥有由MiddleInterface扩展的SubInterface和由SuperInterface扩展的MiddleInterfaceSubInterface怎么SubInterface

public interface SuperInterface { default void printName() { System.out.println("SUPERINTERFACE"); } 
}
public interface MiddleInterface extends SuperInterface { @Override default void printName() { System.out.println("MIDDLEINTERFACE"); } 
}
public interface SubInterface extends MiddleInterface { @Override default void printName() { System.out.println("SUBINTERFACE"); } 
}
public class Implementation implements SubInterface { public void anyOldMethod() { // Do something here } public static void main(String[] args) { SubInterface sub = new Implementation(); sub.printName(); MiddleInterface middle = new Implementation(); middle.printName(); SuperInterface sup = new Implementation(); sup.printName(); } 
}

无论用哪种方式剪切, printName()都将始终打印“ SUBINTERFACE”。

当您具有包含相同方法签名的类和接口时,会出现相同的问题:哪个方法在运行? 答案是“阶级胜利”法则。 接口默认方法将始终被类方法所忽略。

public interface AnyInterface { default String someMethod() { return "This is the interface"; } 
}
public class AnyClass implements AnyInterface { @Override public String someMethod() { return "This is the class - WINNING"; } }

运行上面的代码将始终打印出:“这是课程-WINNING”

最后,如果一个类实现两个接口并且都包含具有相同签名的方法,会发生什么? 这是古老的C ++钻石问题 ; 您如何解决歧义? 运行哪种方法?

public interface SuperInterface { default void printName() { System.out.println("SUPERINTERFACE"); } 
}
public interface AnotherSuperInterface { default void printName() { System.out.println("ANOTHERSUPERINTERFACE"); } 
}

在Java 8的情况下,答案都不是。 如果您尝试同时实现这两个接口,则会收到以下错误:

Duplicate default methods named printName with the parameters () and () are inherited from the types AnotherSuperInterface and SuperInterface.

在绝对必须实现两个接口的情况下,解决方案是调用“类获胜”规则并覆盖实现中的歧义方法。

public class Diamond implements SuperInterface, AnotherSuperInterface { /** Added to resolve ambiguity */ @Override public void printName() { System.out.println("CLASS WINS"); } public static void main(String[] args) { Diamond instance = new Diamond(); instance.printName(); } }

何时使用默认方法

从纯粹的角度来看,默认方法的添加意味着Java接口不再是接口。 接口被设计为用于拟议/预期行为的规范或合同:实施类必须履行的合同。 添加默认方法意味着接口和抽象基类之间实际上没有区别3 。 这意味着他们容易受到滥用,因为一些经验不足的开发人员可能认为从其代码库中删除基类并用基于默认方法的接口替换它们很酷–只是因为它们可以,而其他人可能只是将抽象类与实现默认值的接口混淆了方法。 我目前建议仅将默认方法用于其预期的使用情况:在不破坏现有代码的情况下改进传统接口。 虽然我可能会改变主意。

1它不是很有用,但是它说明了一点……

2肯尼迪(John F Kennedy)的就职演说1961年1月20日。

3抽象基类可以具有构造函数,而接口则不能。 类可以具有私有实例变量(即状态)。 接口不能。

翻译自: https://www.javacodegeeks.com/2014/08/default-methods-java-8s-unsung-heros.html

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

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

相关文章

用phpstudy配置网站遇到的一些问题

第一次是配置在我本机&#xff0c;总是连不上数据库&#xff0c;后来查看到mysql.ini配置文件里面端口号有一个不是3306&#xff0c;更改之后就好了。 第二次是配置在笔记本电脑上&#xff0c;安装的时候比较顺利&#xff0c;也就遇到80端口被占用还有缺少VC运行库的问题&#…

二进制和十进制的相互转换

十进制转二进制&#xff1a; 方法一&#xff1a;y…… 25 * x 24 * x 23 * x 22 * x 21 * x 20 * x&#xff0c;其中y是十进制数字&#xff0c;x是0或1。 方法二&#xff1a; 二进制转十进制&#xff1a; 10100125 * 1 24 * 0 23 * 1 22 * 0 21 * 0 20 * 141 更多专业前端知…

Teradata Expression 12 在Windows 2003上Connection Reset 问题的解决方法

Teradata Expression 12 安装在Windows 2003上&#xff08; 企业版 sp2&#xff09;&#xff0c;完全按照安装手册指导安装。安装过程一切顺利。完成后重启系统。通过Teradata Service Control启动一切正常。状态显示Teradata Running&#xff0c;打开session info ,可以看到一…

Hadoop开发工具简介

几天前&#xff0c; Apache Hadoop开发工具 &#xff08;又名HDT &#xff09;发布了。 这些项目旨在将插件引入eclipse中&#xff0c;以简化Hadoop平台上的开发。 该博客旨在概述HDT的一些重要功能。 单端点 该项目可以充当HDFS&#xff0c;Zookeeper和MR群集的单个端点。 您…

分布式理论之一:Paxos算法的通俗理解

https://www.cnblogs.com/esingchan/p/3917718.html转载于:https://www.cnblogs.com/JBLi/p/10732044.html

UML 面向对象分析与设计

面向对象方法以其超越传统方法的技术先进性越来越得到更多的重视&#xff0c;但技术的先进性不能完全代表一种新生事物的最后成功&#xff0c;还要看它是否能得到有效的推广。统一建模语言&#xff08;UML&#xff09;的产生为这种推广规定了一致的表示&#xff0c;诸多开发过程…

MVC 之var与dynamic

如果你用MVC写过程序&#xff0c;那么你应该知道ViewBag这个用于前后台的数据传递工具&#xff0c;那么你是否对ViewBag的用法感到过疑惑呢&#xff1f; ViewBag.Mode1lnew object();ViewBag.Model2new object();ViewBag.Model3new object();...... 我们知道&#xff0c;在使用…

使用Spring MVC时的常见错误

当我大约10年前开始我的职业生涯时&#xff0c;Struts MVC就是市场上的常态。 但是&#xff0c;多年来&#xff0c;我观察到Spring MVC逐渐流行起来。 鉴于Spring MVC与Spring容器的无缝集成以及它提供的灵活性和可扩展性&#xff0c;这对我来说并不奇怪。 从到目前为止的Spri…

CopyOnWriteArrayList

CopyOnWriteArrayList&#xff0c;add&#xff0c;引用赋值是原子操作吗&#xff1f; 引用类型的读写均是原子操作&#xff0c;https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7&#xff0c;https://www.v2ex.com/t/280788 转载于:https://www.cnblogs…

Statement与PreparedStatement区别

1.性能区别 Statement statement conn.createStatement(); PreparedStatement preStatement conn.prepareStatement(sql); 执行的时候: ResultSet rSet statement.executeQuery(sql); ResultSet pSet preStatement.executeQuery(); 由上可以看出&#xff0c;PreparedState…

C++ operator操作符重载(++,--,-,+,())

C中,--操作符重载需要说明是(--)在操作数前面,还是在操作数后面,区别如下: 代码经过测试无误(起码我这里没问题^_^)Code1#include <iostream> 2#include <cstdlib> 3using namespace std; 4template<typename T> class A 5{ 6public: 7 A(): m_(0){ 8 …

CSS3-2

倒圆角 <!DOCTYPE html><html lang"en"><head> <meta charset"UTF-8"> <title>Document</title></head><body> <h1>圆角边框 —— border-radius IE9</h1> <!-- border-radius 是复合属性…

JavaFX技巧9:请勿混用Swing / JavaFX

JavaFX团队非常努力地说服我们&#xff0c;因为可以将Swing内容嵌入JavaFX UI中&#xff0c;因此可以很容易地从Swing迁移到JavaFX。 我必须承认&#xff0c;我从来没有亲自尝试过&#xff0c;但是根据我从客户那里得到的反馈&#xff0c;我只能建议不要将Swing和JavaFX混合使用…

[ZJJOI2013]K大数查询 整体二分

[ZJJOI2013]K大数查询 链接 luogu 思路 整体二分。 代码 #include <bits/stdc.h> #define ll long long using namespace std; const ll _5e57; ll read() {ll x0,f1;char sgetchar();for(;s>9||s<0;sgetchar()) if(s-) f-1;for(;s>0&&s<9;sgetchar(…

javax.el.PropertyNotFoundException: Property [Xxxx] not found on type Xxx.xxx.xxxx.Xxxx]的解决办法...

当我将后台数据传递给jsp&#xff0c;用${requestScope.user.Id}取值时报错&#xff0c; 最后发现entity实体类的属性不能首字母大写然后再小写&#xff0c;例如 int Age&#xff1b;这个就不行&#xff0c;必须写成int age; 最后问题解决了 转载于:https://www.cnblogs.com/Th…

react学习目录

前面的话 React是如今热门的两大前端框架之一&#xff0c;它设计思路独特&#xff0c;性能卓越&#xff0c;逻辑简单&#xff0c;受到了大量开发者的喜爱。Vue的基本思路是基于HTML模板的扩展&#xff0c;而React的基本思路是基于JS语言的扩展。由于Vue的写法更接近于传统&…

JavaFX技巧13:学习Modena CSS文件

到目前为止&#xff0c;这是最简单&#xff0c;最短的提示。 如果要执行以下任何操作&#xff1a; 了解如何使用CSS 使您的自定义控件看起来像标准控件 重用标准控件使用的SVG路径图形&#xff08;例如&#xff0c;滚动条箭头&#xff09; 弄清楚如何浏览标准控件的结构 确…

委托之异步

在 使用BackgroundWorker组件 一文中&#xff0c;阐述了在Winform编程中&#xff0c;使用BackgroundWorker组件实现异步调用&#xff0c;本文主要讲述利用委托实现异步。 以下描述摘抄于MSDN: 异步委托提供以异步方式调用同步方法的能力。 当同步调用委托时&#xff0c;Invoke(…

[NOI2010]超级钢琴 主席树

[NOI2010]超级钢琴 链接 luogu 思路 和12省联考的异或粽子一样。 堆维护n个左端点&#xff0c;每次取出来再放回去次 代码 #include <bits/stdc.h> #define ll long long using namespace std; const int _5e57,INF0x3f3f3f3f; int read() {int x0,f1;char sgetchar();fo…

【MSP430单片机】IIC 篇

一、转载于:https://www.cnblogs.com/wangsure/p/10734745.html