Java 8新特性简介
- Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。
- Java 8 是oracle公司于2014年3月发布,可以
看成是自Java 5 以来最具革命性的版本
。
Java 8为Java语言、编译器、类库、开发工具与JVM
带来了大量新特性。
.
.
Java 8 新特性
- 速度更快
- 代码更少(增加了新的语法:
Lambda 表达式
) - 强大的
Stream API
- 便于并行
- 最大化减少空指针异常:Optional
- Nashorn引擎,允许在JVM上运行JS应用
.
.
并行流与串行流
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比较串行的流,并行的流可以很大程度上提高程序的执行效率。
Java 8
中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API
可以声明性地通过parallel() 与 sequential()
在并行流与顺序流
之间进行切换。
.
.
.
Lambda表达式
- Lambda 是一个
匿名函数
,我们可以把 Lambda 表达式理解为是一段可以传递的代码
(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。 - Lambda表达式的本质:作为
函数式接口
的实例
。
1、如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。
2、我们可以在一个接口上使用@FunctionalInterface 注解
,这样做可以检查它是否是一个函数式接口。
- 所以以前用
匿名实现类表示的现在都可以用Lambda表达式来写。
.
.
语法:
- “->”:lambda表达式的
操作符 或 箭头操作符
,它将Lambda 分为两个部分
。 - “->”的左边:指定lambda表达式的
形参列表
(其实就是接口中抽象方法的形参列表
) - “->”的右边:指定了 Lambda
体
,是抽象方法的实现逻辑(其实就是重写方法的抽象方法的方法体
)
总结:
->左边:lambda形参列表的类型可以省略;如果lambda形参列表只有一个参数,其一对()也可以省略;
->右边:lambda体应该使用一对{}包裹,如果lambda体只有一条执行语句(包括return语句),可以省略这一对{}和return关键字;
.
.
函数式(Functional)接口
-
只包含一个抽象方法的接口
,称为函数式接口
。 -
你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。
-
我们可以在一个接口上使用
@FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口
. -
在java.util.function包下定义了Java 8 的丰富的函数式接口
.
.
.
方法引用与构造器引用
.
方法引用(Method References)
- 使用情境:当要传递给Lambda体的操作,已经有
实现的方法
了,可以使用方法引用! 方法引用
,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也就是函数式接口的实例。- 格式:使用操作符 “
::
” 将类(或对象) 与 方法名分隔开来。 - 如下三种主要使用情况:
情况1对象::实例方法名
情况2类::静态方法名
情况3类::实例方法名
.
方法引用的要求:
接口中的抽象方法的形参列表和返回值类型与 方法引用 的方法的形参列表和返回值类型相同!(针对于情况1和情况2)
接口中的抽象方法的形参列表的第一个参数可以作为 方法引用 的方法的调用者!(针对于情况3)
.
.
构造器引用
- 格式:
类名::new
- 要求:和 方法引用 类似,
构造器参数列表要与接口中抽象方法的参数列表一致!且方法的返回值即为构造器对应类的对象。
.
.
数组引用
- 格式:
数据类型[] :: new
- 可以吧数组看做是一个特殊的类,写法就和构造器引用一样。
.
.
.
强大的Stream API
一、Stream API说明
- Java8中有两大最为重要的改变。
第一个是 Lambda 表达式
;另外一个则是 Stream API
。 Stream API ( java.util.stream)
把真正的函数式编程风格引入到Java中
。这是目前为止对Java类库最好的补充。- Stream 是 Java8 中
处理集合的关键抽象概念
,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。
- 也可以使用 Stream API 来并行执行操作。
- 简言之,Stream API 提供了一种
高效且易于使用的处理数据的方式。
.
.
二、为什么要使用Stream API?
- 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有
MongDB,Radis等,而这些NoSQL的数据就需要Java层面(Stream API)去处理。
- Stream 和 Collection 集合的区别:
Collection 是一种静态的内存数据结构,而 Stream 是有关计算的(对内存中的数据进行操作)。
前者是主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。
.
.
三、什么是 Stream?
- Stream是数据渠道,用于
操作数据源(集合、数组等)所生成的元素序列
。
“集合讲的是数据,Stream讲的是计算!”
- 注意:
①Stream 自己不会存储元素。(和Iterator性质一样
)
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行(执行终止操作,才执行中间操作链中的操作
)详情:以下操作步骤图👇
.
.
四、Stream 的操作三个步骤
.
.
创建Stream
方式一、通过集合
- Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流
.
方式二:通过数组
- Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
static <T> Stream<T> stream(T[] array): 返回一个流
- 重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
.
方式三:通过Stream的of()
- 可以调用Stream类静态方法 of(), 通过显示值创建一个流。它可以接收任意数量的参数。
public static<T> Stream<T> of(T... values) : 返回一个流
.
方式四:创建无限流
- 可以使用静态方法
Stream.iterate()
和Stream.generate()
, 创建无限流。
迭代:public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
生成:public static<T> Stream<T> generate(Supplier<T> s)
.
.
.
Stream 的中间操作
- 多个中间操作可以连接起来形成一个
流水线
。 - 除非流水线上
触发终止操作
,否则中间操作不会执行任何的处理
!(要调用终止操作,才能执行中间件操作
) - 而在终止操作时一次性全部处理,称为“惰性求值”。
执行一次终止操作,就不能在重新操作数据,需要重新创建一个Stream,才能在操作数据。
(和Iterator性质一样
)
.
一、筛选与切片
.
二、映射
按照某种方式得到另外的值!!!!
-
map(Function f)
:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
例:返回元素变为大写
Stream.of(“aa”,“bb”,“cc”).map(s -> s.toUpperCase()).forEach(System.out::println); -
flatMap(Function f)
:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
参数如果还是Stream类型的,不会只遍历Stream类型,而是遍历到不是Stream类型元素为止。
.
三、排序
.
.
.
Stream 的终止操作
- 终端操作会从流的流水线生成结果。其
结果可以是任何不是流的值
,例如:List、Integer,甚至是 void 。 流进行了终止操作后,不能再次使用。
.
.
一、匹配与查找
.
二、归约
- 备注:
map 和 reduce 的连接通常称为 map-reduce 模式
,因 Google 用它来进行网络搜索而出名。
.
三、收集
- Collector 接口中方法的实现
决定了如何对流执行收集的操作(如收集到 List、Set、Map)。
Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例
,如下:
.
.
.
Optional类
为了在容器中避免空指针而创建!!!!
- Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。
原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
- Optional类的Javadoc描述如下:
这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
- Optional提供很多有用的方法,这样
我们就不用显式进行空值检测。
.
Optional类常用方法