Java开发笔记(六十二)如何定义函数式接口
2019-02-25 16:09:58来源:博客园 阅读 ()
前面介绍了Lambda表达式的用法,从实践中发现它确实极大地方便了开发者,然而不管是匿名内部类还是Lambda表达式,所举的例子都离不开各类数组的排序方法,倘使Lambda表达式仅能用于sort方法,无疑限制了它的应用范围。那么除了sort方法,还有哪些场景能够将Lambda表达式派上用场呢?既然匿名内部类与Lambda表达式都依附于某种接口,追根究底,就得好好研究一下这种接口的特别之处。
关于排序方法sort的第二个输入参数,原本定义的参数类型是比较器Comparator,可是这个比较器真正有用的实乃唯一一个抽象方法compare。之前阐述Lambda表达式概念的时候,提到Lambda表达式指的是匿名方法,并且由于Java不支持把方法作为参数类型,因此只好再给方法加一层接口的包装,于是sort方法里的参数类型变为Comparator接口而非compare方法了。
像Comparator这种挂羊头卖狗肉的接口,表面上是接口的结构,实际上给某个方法专用,为了有别于其它普通接口,它被Java称作“函数式接口”。函数式接口拥有一般接口的形态,但其内部有且仅有一个抽象方法(方法也叫做函数),而这也是外部调用时采取Lambda表达式改写的方法。除此之外,函数式接口还允许定义别的非抽象方法,包括默认方法与静态方法。
搞清楚了函数式接口的来龙去脉,接下来不妨自定义一个全新的函数式接口。之前讲到普通接口之时,定义了一个行为接口给各个动物类实现,这意味着行为动作的方法代码与类定义代码在一起定义。如果来了一个新的动物,就得提供对应的动物类定义及其动作代码,日积月累各种动物类势必越来越多。不过很多业务场景希望更灵活的逻辑,往往只要定义一个基础的动物类,然后动物的每样属性都由成员方法读写,甚至动物的行为动作也由外部传入。这样可以制定一个“行动”方法,并通过“行为”接口包装起来,再提供给动物类使用。下面便是一个最简单的行为接口代码例子:
//定义一个行为接口,给动物类调用 public interface Behavior { // 声明一个名叫行动的抽象方法 public void act(); }
从上面的接口定义可知,Behavior接口有且仅有一个抽象方法act,因而它属于函数式接口。接着编写动物类的定义代码,其中的midnight方法用来控制该动物在半夜干什么,具体的行动内容由输入参数指定(参数类型为Behavior),具体的动物类代码如下所示:
//演示动物类的定义,其中midnight方法的输入参数为Behavior类型 public class Animal { // 定义一个名称属性 private String name; public Animal(String name) { this.name = name; } public String getName() { return this.name; } // 定义一个半夜行动的方法。具体的动作由输入行为的act方法执行 public void midnight(Behavior behavior) { behavior.act(); } }
然后外部就能创建动物类Animal的实例,并调用该实例的midnight方法传入规定的行为动作。以公鸡为例,大公鸡最喜欢在半夜鸡叫了,那么先创建一只公鸡实例,再命令它的midnight方法执行叫唤动作,这里的叫唤动作若以匿名内部类书写的话,可参考下列的调用代码:
// 测试公鸡在半夜干了啥 private static void testCock() { Animal cock = new Animal("公鸡"); // 调用midnight方法时,传入匿名内部类的实例 cock.midnight(new Behavior() { @Override public void act() { System.out.println(cock.getName()+"在叫啦。"); } }); }
把以上的匿名内部类写法改为Lambda表达式,将冗余部分掐头去尾简化成了如下一行代码:
// 调用midnight方法时,传入Lambda表达式的代码。 // 匿名方法不存在输入参数的话,也要保留一对圆括号占位子。 cock.midnight(() -> System.out.println(cock.getName()+"在叫啦。"));
单单看这个Lambda表达式,姑且不论事实上的参数类型为何,至少在表面上是把一段方法代码作为输入参数传给了midnight。如此一来,函数式接口借助Lambda表达式,成功地瞒天过海摇身变成了一种方法类型。
继续演示其它动物,每当夜深人静的时候,老猫便瞪圆眼睛出来捉老鼠了,于是往老猫实例的midnight方法输入捉老鼠动作,相应的调用代码如下所示:
// 测试老猫在半夜干了啥 private static void testCat() { Animal cat = new Animal("老猫"); // 调用midnight方法时,传入Lambda表达式的代码 cat.midnight(() -> System.out.println(cat.getName()+"在捉老鼠。")); }
可见函数式接口结合Lambda表达式,将与行为有关的代码减肥减得不能再瘦了。再奉上一段猪仔在半夜呼呼大睡的代码例子:
// 测试猪仔在半夜干了啥 private static void testPig() { Animal pig = new Animal("猪仔"); // 调用midnight方法时,传入Lambda表达式的代码 pig.midnight(() -> System.out.println(pig.getName()+"在呼呼大睡。")); }
最后运行上述三种动物的测试代码,得到以下的日志结果:
公鸡在叫啦。 老猫在捉老鼠。 猪仔在呼呼大睡。
总结一下,函数式接口适用于外部把某个方法当作输入参数的场合。通过利用函数式接口,一群相似的实体支持在调用之时单独传入个体动作,而无需像从前那样派生出许多子类,还要在各个子类中分别实现它们的动作方法。
更多Java技术文章参见《Java开发笔记(序)章节目录》
原文链接:https://www.cnblogs.com/pinlantu/p/10415868.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash