【黑马程序员济南中心】JDK1.8新特性Lambda表达式和Function接口

引言

    大家的安卓基础班课程是基于jdk7的,但是在每个学生开班入学的时候电脑上几乎都是安装的jdk8,因为大家总觉得新版的就是最好的,但其实这种认识是错误的。一门技术从出现到成熟再到普遍使用是要经历很长时间的,比如jdk6是在2006年12月12日发布的,而它真正的被在开发当中广泛被采用也是近几年的事情了,因为毕竟刚刚出现的技术可能会存在很多的bug以及不兼容因素,需要经历一段时间去发现和解决,最终达到一个成熟的版本而被广大技术人员所应用。同样的道理,jdk8也是这样的,但是jdk8早晚会有被广泛应用到实际项目中去的一天,所以接下来我就为大家来讲解一下jdk8中最大的卖点 - Lambda表达式。

背景   

    Lamda是一种基于函数的编程语言(也就是咱们课上讲面想对象时候说的面向过程语言),对于这种类型的语言典型的代表就是Haskell,但是Java是面向对象编程语言,一切的操作都是必须有类,所有的功能都必须定义在类之中,所以这就造成了一点弊端,也就是很多习惯于函数编程的开发者就觉得Java不好用,但也并不是说Java中没有基于函数编程的语法体现,只不过稍微麻烦些,那么他的实现模式就是匿名内部类(就是咱们说的接口的匿名的子类对象,可以不用创建类,就能创建出一个接口的子类对象),于是在Java诞生20年之后,Java终于推出了Lamda表达式,其最要的目的是解决匿名内部类的书写麻烦问题,而且由于能够在纯Java语言环境中提供一种优雅的方式来支持函数式编程,也使它具有吸引越来越多程序员到Java平台上的潜力。

案例演示

    首先我们在讲解Lamda表达式之前,先来回顾一下我们的匿名内部类如何定义?请看下面的代码。

package com.heima.lamda;

interface Inter{                                //如果使用匿名内部类必须先存在一个接口

        public void print(String str);    //使用匿名内部类实现的接口,一般里面只有一个方法

}

public class Demo {

        public static void main(String[] args) {

                Inter it = new Inter() {          //使用匿名内部类,让父类的引用指向子类对象

                        public void print(String str) {    //重写接口中的方法

                                System.out.println(str);

                        }

                }; 

                it.print("helloWorld");            //父类的引用调用子类重写后的方法

        }

}

以上代码就是在jdk1.8之前我们写匿名内部类的代码,其实上面的代码我们真正需要的就是一个输出语句,却写了这么一大堆的代码。 而且这也是我们写的最简单的代码了,因为要想利用一个接口里面的方法去打印一个HelloWorld,只能先创建一个类实现接口并重写其中的方法,然后创建该类对象,从而调用方法进行打印,这时候匿名内部类就是我们能写出的最精简的代码了,这是由于java之中类结构的强制限制,所以很多人就觉得代码过于麻烦了。但是Lambda表达式的出现很好的解决了这一问题,那么下面我们就用Lambda表达式来演示上面的案例:

package com.heima.lamda;

interface Inter{                                      //Lambda表达式只试用与实现接口的匿名内部类

        public void print(String str);        //Lambda表达式要求接口里面必须必须只能有一个抽象方法

}

public class Demo {

        public static void main(String[] args) {

                Inter it = (s) -> System.out.println(s);//Lambda表达式 ,s就是接口里的方法参数             

                it.print("helloWorld");              //父类的引用调用子类重写后的方法

        }

}

首先,先不看语法,至少通过上面的程序我们发现,使用了Lambda表达式,这个语句少了,更简单了,没有了类结构的控制。      那么上面整个实现的Lambda表达式语句是:  (s) -> System.out.println(s);   

Lambda格式

Lambda表达式的结构是:   (参数)  ->  函数体;

参数:参数名可以随便起名字,毕竟是标示符嘛,他的类型与Inter接口定义的print(String str)方法里面的参数类型一致,但是此处没有必要进行声明,因为这个参数类型是由编译器推测出来的。同时,你也可以直接给出参数的类型,也就是:

(String s) -> System.out.println(s);          

->   :     是一个固定语法,表示将参数指向方法体。

函数体:即方法体,就是以前编写在匿名内部类实现方法里面的方法体。

注意事项:

  1.  在某些情况下lambda的函数体会更加复杂,这时可以把函数体放到在一对花括号中,就像在Java中定义普通函数一样。例如:

 (s) -> { System.out.println(s); System.out.println(s+"HelloWorld");

                                     };  

  2.  Lambda表达式中的函数体也就是匿名内部类中的方法体, 所以在Lambda表达式的方法体中使用局部变量,局部变量前面也必须加final修饰,而再jdk8中如果这些变量不是final的话,它们会被隐含的转为final,这样效率更高

  3.  有时候接口中的抽象方法会有返回值,Lambda也就会返回一个值。返回值的类型也是由编译器推测出来的。如果lambda的函数体只有一行的话,那么没有必要显式使用return语句。下面两个代码片段是等价的:

package com.heima.lamda;

interface Inter{                                                               

        public String getString(String str);                               

}

public class Demo {

        public static void main(String[] args) {

                Inter it = (s) -> s;             

                String str = it.getString("hello");

                System.out.println(str);    //打印出 hello

        }

}

上面的代码和下面的代码是等价的

package com.heima.lamda;

interface Inter{                                                               

        public String getString(String str);                               

}

public class Demo {

        public static void main(String[] args) {

                Inter it = new Inter() {               

                        public String getString(String str) {       

                                return str;

                        }

                };               

                String str = it.getString("hello");

                System.out.println(str);    //打印出 hello

        }

}

4.   Lambda表达式只适用于 接口的匿名内部类,而且接口中必须有且只有一个抽象方法

Functional接口

       我们了解到Lambda表达式只适用于接口中有且只有一个抽象方法的情况,那如果再开发过程中有开发者不小心给接口添加了多个抽象方法,那么就不再支持Lambda了,语言设计者投入了大量精力来思考如何使现有的函数友好地支持lambda。最终采取的方法是:增加函数式接口的概念。函数式接口就是一个具有一个方法的普通接口。像这样的接口,可以被隐式转换为lambda表达式。java.lang.Runnable与java.util.concurrent.Callable是函数式接口最典型的两个例子。在实际使用过程中,函数式接口是容易出错的:如有某个人在接口定义中增加了另一个方法,这时,这个接口就不再是函数式的了,并且编译过程也会失败。为了克服函数式接口的这种脆弱性并且能够明确声明接口作为函数式接口的意图,Java 8增加了一种特殊的注解@FunctionalInterface(Java 8中所有类库的已有接口都添加了@FunctionalInterface注解)。让我们看一下这种函数式接口的定义

package com.heima.lamda;

@FunctionalInterface

interface Inter{                                                               

        public String getString(String str);       

}

把这种注解写在接口上面,当开发人员想继续写抽象方法的时候,Eclipse就会报红色波浪线提示编译失败,这和@Override注解有些类似,下面我们也举例说明@Override注解:

interface Inter{

        public String getString(String str);       

}

public class Demo implements Inter{

        @Override

        public String getString(String str) {

                return str;

        }       

}

将@Override注解写在重写的方法的上面,如果你在书写方法声明的时候有一点和被重写的方法不一样的地方,Eclipse也会立刻报出红色波浪线提示编译失败。

总结

毫无疑问,jdk8发行版是自jdk5(发行于2004,已经过了相当一段时间了)以来最具革命性的版本。jdk8为Java语言、编译器、类库、开发工具与JVM(Java虚拟机)带来了大量新特性。在这篇教程中,我只介绍了jdk8最大的亮点Lambda表达式,以及为Lambda表达式专门设计的函数式接口。希望对大家有所帮助,如果大家对这篇教程感兴趣的话,敬请阅读大山哥哥的下一篇教程吧~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容