带你深入JAVA8的新特性
简介
Oracle在2014年3月份发布了java8正式版,该版本增加了很多新特性,比如:函数式接口、lambda表达式、集合的流式操作、注解的更新、安全性增强、IO\NIO的改进
函数式接口
什么是函数式接口
这是java8的一个核心概念,(Functional Interfaces).通过在接口中添加一个抽象方法,这些方法可以直接从接口中运行。我们有两种方法去实现一个函数式接口
1. 在一个接口中定义唯一一个抽象方法,那么这个接口就成为函数式接口
2. 通过注解@functionalInterface,用来标注这个接口是一个函数式接口。推荐这种写法,好处是如果接口不符合函数式接口的定义时,编译器会报错
Java.lang.Runnable就是一个典型的函数式接口;
函数式接口的用途
主要用在Lambda表达式和方法引用上
代码演示
这里写图片描述
这里写图片描述
函数式接口的特性
函数式接口允许定义静态方法
函数式接口允许定义default方法
函数式接口里允许定义java.lang.Object里的public方法
这里写图片描述
泛型及继承关系
接口可以继承接口,如果一个父接口是一个函数接口,那么子接口也有可能是一个函数式接口,那么它的判断依据是什么呢?
对于接口I, 假定M是接口成员里的所有抽象方法的继承(包括继承于父接口的方法), 除去具有和Object的public的实例方法签名的方法, 那么我们可以依据下面的条件判断一个接口是否是函数式接口, 这样可以更精确的定义函数式接口。
如果存在一个一个方法m, 满足:
• m的签名(subsignature)是M中每一个方法签名的子签名(signature)
• m的返回值类型是M中的每一个方法的返回值类型的替代类型(return-type-substitutable)
那么I就是一个函数式接口。
情况一
这里写图片描述
接口Z继承了X,Y接口的m方法,由于这两个方法的签名相同,返回值也一样,所以Z有唯一的一个抽象方法int m(List arg);,可以作为函数式接口。
情况二
这里写图片描述
方法签名Y.m既满足签名是X.m,并且返回值也满足,所以Z仍然是函数式接口
情况三
这里写图片描述
编译出错,因为没有一个方法的签名是所有方法的子签名
Java.util.function
Lambda表达式在运行期间表示为一个接口函数,而接口函数只是一种只定义了一个抽象方法的接口。尽管java8里面已经有一些接口符合函数式接口的定义,比如Runnable , Comparator。但是对于我们来说显然是不够的。而如果我们需要在程序里使用非函数数接口来实现lambda表达式的操作,那么怎么去做? Java8引入了一个新增的包java.util.function, 专门用来解决这个问题。这个包里提供了很多接口
Lambda表达式
函数式接口的重要属性是:我们能够使用Lambda来实例化他们,Lambda表达式让你能够将函数作废方法参数,或者将代码作为数据对待。
优点
在java8出现之前,匿名内部类,监听器和事件处理的使用都显得很冗长,代码可读性差,而Lambda表达式的应用能够是代码变得更加紧凑,可读性增强
语法
Lambda表达式由三个部分组成:
第一部分:一个括号内用逗号分割形式参数,参数是函数式接口里面方法的参数
第二部分:一个箭头号 ->
第三部分:方法体,可以是表达式和代码块
情况一
方法体为表达式,则该表达式的值作为返回值返回:
情况二
方法体为代码块,必须要用{}包裹起来,如果该接口有返回值,则需要return返回值,反之则不需要
这里写图片描述
代码演示
情况1, 对内部类进行简化
这里写图片描述
情况2,我们用list排序来演示效果
这里写图片描述
大家可以点击加入群:606187239【JAVA大牛交流学习】
里面有Java高级大牛直播讲解知识点 走的就是高端路线 (如果你想跳槽换工作 但是技术又不够 或者工作上遇到了瓶颈 我这里有一个JAVA的免费直播课程 讲的是高端的知识点基础不好的误入哟 只要你有1-5年的开发经验可以加群找我要课堂链接 注意:是免费的 没有开发经验误入哦)
简化处理后
这里写图片描述
方法引用
有时候Lambda表达式的代码只是一个简单的方法调用而已,而遇到另外一种情况我们可以更进一步去简化,我们称之为方法引用;
引用静态方法
引用对象的实例方法
引用某个类型的任意对象的实例方法
引用类构造函数
代码演示
我们同样针对一个数组进行排序,综合以上所有提到的方法引用类型
第一步
第二步
第三步
集合流式操作
Java8引入了流式操作(Stream),通过该操作可以实现对集合的并行处理和函数式操作。
1. 根据操作返回的结果不同,流式操作又分为中间操作和最终操作。最终操作返回的是一个特定类型的结果;而中间操作返回的是流本身,因此就可以将多个操作一次串联起来;
2. 根据流的并发性、又可以分为串行和并行两种,流式操作实现了对集合的过滤、排序、映射等功能
串行流和并行流
通过串行流操作是在一个线程中依次完成,而并行流则是在多个线程上同时执行。并行和串行的流操作可以相互切换:通过
Stream.sequential()返回串行流
Stream.parallel() 返回并行流
相比于串行流,并行流可以很大程度上提高程序的执行效率
串行/并行排序演示
中间操作
该操作会保持 stream 处于中间状态,允许做进一步的操作。它返回的还是的 Stream,允许更多的链式操作。常见的中间操作有:
filter():对元素进行过滤;
sorted():对元素排序;
map():元素的映射;
distinct():去除重复元素;
subStream():获取子 Stream 等。
终止操作
该操作必须是流的最后一个操作,一旦被调用,Stream 就到了一个终止状态,该操作之后不能再链式的添加其他操作。常见的终止操作有:
forEach():对每个元素做处理;
toArray():把元素导出到数组;
findFirst():返回第一个匹配的元素;
anyMatch():是否有匹配的元素等。