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

java8 默认方法

几周前,我写了一个博客,说开发人员学习新语言是因为它们很酷。 我仍然坚持这个主张,因为关于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

java8 默认方法

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

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

相关文章

两个常见的并发错误

作为Baeldung的编辑&#xff0c;我很高兴与一位作者一起撰写有关Java通用并发陷阱的文章。 这是一本不错的书&#xff0c;但是假设开发人员具有一定的能力。 我已经看到了几件即时并发失败的事情。 它们很容易添加到代码中&#xff0c;并保证为您提供奇怪的结果。 开发人员仍会…

kotlin自定义View出现 java.lang.ClassNotFoundException

问题1&#xff1a;找不到所引用的自定义View Didn’t find class “dxf.example.dxf.customviewdemo.MyTextView” on path: DexPathList 原因&#xff1a;build.gradle中 应用插件 解决&#xff1a;添加 apply plugin: ‘kotlin-android’ 问题2&#xff1a; java.lang.Cl…

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

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

kotlin-unresolved reference daclaredFunctions

问题&#xff1a;如题 原因&#xff1a; 默认编译时不导入kotlin-reflect.jar包导致&#xff0c;所以在该包中的默认不能使用 解决 需额外在dependencies中添加 kotlin-reflect的编译&#xff0c; compile “org.jetbrains.kotlin:kotlin-reflect:$kotlin-version”

AWS Loft的数据库周

这是我的笔记&#xff1a; https://databaseweekoctober2019sf.splashthat.com AWS上的数据库&#xff1a;正确工作的正确工具 在许多此类谈话中&#xff0c;我并没有做过深刻的记录。 我正在关注重点。 PostgreSQL排在MySQL之后。 AWS上8种类型的数据库&#xff1a; 关系…

MockWebServer[45678] connection from null failed: java.net.SocketException

MockWebServer使用中的异常 MockWebServer: MockWebServer[45678] connection from null failed: java.net.SocketException: sendto failed: EBADF (Bad file number) java.io.IOException: unexpected end of stream on Connection Caused by: java.io.EOFException: \n n…

ExternalDocumentationLinkImpl(url=https://developer.android.com/reference/, packageListUrl=https://d

dokka 问题 java.lang.RuntimeException: Exception while loading package-list from ExternalDocumentationLinkImpl(urlhttps://developer.android.com/reference/, packageListUrlhttps://developer.android.com/reference/package-list) 原因 使用了下面这个任务定义…

IntellijIDEA插件编写-删除/插入/替换文档内容

错误 ERROR - plication.impl.ApplicationImpl - Assertion failed: Write2018-03-24 01:57:49,835 [ 138880] ERROR - plication.impl.ApplicationImpl - Assertion failed: Write access is allowed inside write-action only (see com.intellij.openapi.application.Appli…

jaxb_JAXB –新手的观点,第1部分

jaxb我知道你们中的很多人已经在想什么&#xff0c;所以让我们摆脱这个问题&#xff1a;“ JAXB&#xff1f; 如XML&#xff1f; 来吧&#xff0c;所有很棒的孩子都在使用JSON。” 关于XML与JSON的辩论以及许多促成它的论据都得到了很好的记录。 我不会花很多时间在这里重新整…

Log4j Bug –减慢您的应用程序

最近&#xff0c;我们正在对流行的SaaS应用程序进行故障排除。 该应用程序间歇性地减慢了速度。 要从问题中恢复&#xff0c;必须重新启动应用程序。 在高流量期间&#xff0c;此应用有时会变慢&#xff1b; 有时在交通繁忙时也是如此。 没有凝聚力模式。 这种应用程序变慢并重…

androidstudio --debug 出现 source code not match bytecode

问题 如标题 原因 编译api版本与运行app的模拟器api版本不一致 解决 换成API版本一致的模拟器运行app即可

android monitor突然不能显示

问题 如题 原因 不清楚。。。。 解决 方式一-有副作用&#xff08;原因不明&#xff09;-debug可能会一直 wait attach&#xff0c;不能进入调试模式 先将Android NDK support plugin禁用&#xff08;重启androidstudio&#xff09;右击android monitor,选择remove from …

jvm虚拟机 基于栈_守护基于JVM的应用程序

jvm虚拟机 基于栈部署体系结构设计是任何定制服务器端应用程序开发项目的重要组成部分。 由于其重要性&#xff0c;部署架构设计应尽早开始&#xff0c;并与其他开发活动一起进行。 部署体系结构设计的复杂性取决于许多方面&#xff0c;包括所提供服务的可伸缩性和可用性目标&a…

ListView中让TextView中的文字进行单独滚动

TextView不能在ListeView中单独的滚动原因 默认ListView将会拦截MOVE事件向下传递 参见源码 case MotionEvent.ACTION_MOVE: {switch (mTouchMode) {case TOUCH_MODE_DOWN:int pointerIndex ev.findPointerIndex(mActivePointerId);if (pointerIndex -1) {pointerIndex 0;…

JPA @Embeddable和@Embedded

介绍&#xff1a; 作为一个面向对象的开发人员&#xff0c;我们希望避免使用带有大量不相关字段的大型类。 因此&#xff0c;我们可能经常感到有必要使用多个对象来表示JPA实体。 在本快速教程中&#xff0c;我们将学习如何使用JPA或Hibernate中的Embedded和Embeddable注释来实…

android monitor不能查看/data目录

问题 在android 7.0虚拟机上不能查看/data目录 解决 1. 修改目录权限 开始->cmd->adb shell->chmod -R 777 /data 2. root虚拟机 先执行 adb root&#xff0c;再执行 adb remount 出现remount succeeded表示可以了

Sqlite error- INSERT failed: datatype mismatch

问题 sqlite3 使用.import命令导入输入出现error-INSERT failed: datatype mismatch 原因 文件字段的默认分隔符为“|”&#xff0c;而从excel转换的.csv文件默认为逗号&#xff0c;所以导致文件解析出错&#xff0c;进而 “数据类型不匹配” 解决 在.import命令前修改分隔…

反射-获取java私有内部类反射类型、私有字段

获取JAVA私有内部类反射类型 方式一 Class.forName(“外部类完整路径$内部私有类类名”); 方式二 通过获取对应私有内部类的字段而获取 完整的类名 Class.forName(field.getType().getName()) 获取JAVA私有字段 Class.forName(“类完整路径”).getDelcaredField(“字段名…

javafx透明边框_JavaFX技巧6:使用透明颜色

javafx透明边框为用户界面元素选择正确的颜色始终是一个很大的挑战&#xff0c;但是当您开发可重用的框架控件时&#xff0c;开发人员就无法控制使用它们的应用程序的外观和感觉&#xff0c;这甚至更具挑战性。 尽管您可能总是将元素添加到默认的灰色背景之上&#xff0c;但是嵌…

android-创建sdcard

进入sdk 安装路径 tools目录下 mksdcard 100M D:\dxfSDCard.img //创建一个100M的sdcard