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 默认方法

java8 默认方法_默认方法:Java 8的无名英雄相关推荐

  1. gdb 扩展 默认参数_默认方法一种扩展旧代码的方法

    gdb 扩展 默认参数 如您所知,Java的新版本已于2014年3月18日发布,我将介绍一系列文章来演示其新功能,也许在某些方面,我将谈论我的想法和批评. 我认为重要的第一个功能是"默认方法 ...

  2. java怎么区分变量和方法_如何测试Java的变量和方法

    方法二:利用安全管理器 安 全性管理器与反射机制相结合,也可以达到我们的目的.Java 运行时依靠一种安全性管理器来检验调用代码对某一特定的访问而言是否有足够的权限.具体来说,安全性管理器是 java ...

  3. java时间中间加横杠方法_知识点:java一些方法会有横线?以Date 过期方法为例...

    原因:他们的开发者在升级方法后,添加了@Deprecated注释, 目的是为了提醒我们,这个方法现在已经有新的方法了,不建议继续使用! 比如: JAVA中Date的tolocalstring为什么不建 ...

  4. java中gettext方法_深入理解Java中方法的参数传递机制

    形参和实参 我们知道,在Java中定义方法时,是可以定义参数的,比如: public static void main(String[] args){ } 这里的args就是一个字符串数组类型的参数. ...

  5. java中的invoke方法_详解Java中Method的Invoke方法

    在写代码的时候,发现从父类class通过getDeclaredMethod获取的Method可以调用子类的对象,而子类改写了这个方法,从子类class通过getDeclaredMethod也能获取到M ...

  6. java 异步调用方法_乐字节Java编程之方法、调用、重载、递归

    一.概述 方法是指人们在实践过程中为达到一定目的和效果所采取的办法.手段和解决方案. 所谓方法,就是解决一类问题的代码的有序组合,是一个功能模块.编程语言中的方法是组合在一起来执行操作语句的集合.例如 ...

  7. python start方法_进程方法 run和start的区别

    start() 方法来启动进程,真正实现了多进程运行,这时无需等待 run 方法体代码执行完毕而直接继续执行下面的代码:调用 Process 类的 start() 方法来启动一个进程,这时此进程处于就 ...

  8. 注解默认继承_默认方法和多重继承

    注解默认继承 最近卢卡斯JOOQ埃德尔发布和文章有关嵌套类及其使用. 这是一个有趣的话题,他的文章一如既往地有趣并且值得一读. 只有一个简短的声明我无法同意,我们有一个简短的回复链,导致了默认方法,以 ...

  9. java thread exit方法_实例分析Java终止线程和stop()方法

    Java终止线程实例和stop()方法源码阅读 了解线程 概念 线程 是程序中的执行线程.Java 虚拟机允许应用程序并发地运行多个执行线程. 线程特点 拥有状态,表示线程的状态,同一时刻中,JVM中 ...

最新文章

  1. 不甘心只做输入工具,搜狗输入法上线AI助手,提供智能服务
  2. java程序设计输入输出实验_20145320《Java程序设计》第五次实验报告
  3. 坐标和变换的数学基础(2)
  4. dismiss的词组_法律英语常用词必记:Dismiss
  5. 太古鸿蒙诀正式版v1.07,百变队长安崎:台上小辣椒,台下情歌王
  6. spring学习(49):javaconfig里面定义bean的作用域
  7. Filecoin Gas基础费率跌至4.40 nanoFIL
  8. iOS传感器开发——加速度传感器,螺旋仪传感器,磁力传感器的应用
  9. 概率论 方差公式_斯坦福 CS229 机器学习课程的数学基础(概率论)翻译完成
  10. Opencv最新版本Opencv3.3.0集成了DNN神经网络模块
  11. uniapp实现微信公众号登录获取openid
  12. win10完美还原桌面图标快捷方式小箭头的方法
  13. 用vim解压各种格式
  14. 导致无法查看隐藏文件的病毒处理
  15. Invalid byte tag in constant pool 19
  16. Java NIO简介
  17. spreadsheet php,关于 PhpSpreadsheet 简单教程
  18. unbuntu下 sudo apt-get update 更新软件源列表
  19. Saruman's Army
  20. 工信部数字电视标准符合性检测中心发布的

热门文章

  1. vijos1197-费解的开关【递推,枚举,位运算】
  2. POJ2481-Cows【树状数组】
  3. 邓公数据结构C++语言版学习笔记1
  4. 2.数据湖DeltaLake之DDL操作
  5. @Resource,@Autowired,@Inject3种注入方式详解
  6. Java 必看的 Spring 知识汇总
  7. IDEA创建包不是树形
  8. ppt2010基础操作笔记
  9. mysql中ifnull函数
  10. 2019蓝桥杯省赛---java---B---6(特别数的和)