Java8新特性
Java8新特性
- Lambda 表达式:Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
- 方法引用 :方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
- 默认方法 :默认方法就是一个在接口里面有了一个实现的方法。
- 新工具 :新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
- Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
- Date Time API : 加强对日期与时间的处理。
- Optional 类 :Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
- Nashorn, JavaScript 引擎 : Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
Lambda表达式
语法格式
lambda表达式的语法格式如下:
1 |
|
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值
- 可选参数圆括号:一个参数无需定义圆括号,但是多个参数需要定义圆括号
- 可选大括号:如果主体只包含一个语句,就不需要使用大括号
函数式接口
函数式接口(Function Interface):是一个接口。这个接口有且仅有一个抽象方法,但是可以有多个非抽象方法。
1 |
|
在函数式编程语言当中,函数被当作一等公民。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中有所不同。在Java8中,Lambda表达式是对象,而不是函数。它们必须依附于一类特别的对象类型——函数式接口而存在。
简单来说,在Java8中,Lambda表达式就是一个函数式接口的实例。只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示(在此之前,完成对应功能的是匿名类)
java.util.function
它包含了很多类,用来支持 Java的
函数式编程。
并且在Java中,有四大核心函数式编程接口:
函数式接口 | 参数类型 | 返回类型 | 说明 |
---|---|---|---|
Consumer<T> |
T | void | 对类型为T的对象应用操作 对应的抽象方法为 void accept(T t) |
Supplier<T> |
无 | T | 返回类型为T的对象 对应的抽象方法为 T get() |
Function<T, R> |
T | R | 对类型为T的对象应用操作并返回类型为R的对象 对应的抽象方法为 R apply(T t) |
Predicate<T> |
T | boolean | 确定类型为T的对象是否满足某约束,返回boolean值 对应的抽象方法为 boolean test(T t) |
方法引用
有时候lambda表达式只涉及一个方法的调用,我们可以使用方法引用。方法引用指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法,调用给定的方法。方法引用的格式如下:
1 |
|
可能的情况有:
类::静态方法
:要求方法和接口参数列表相同实例::非静态方法
:要求方法和接口参数列表相同类::非静态方法
:接口中第一个参数来调用该方法,方法参数为剩余参数
方法引用最终也是对应到一个lambda表达式,从而对应到一个实现接口的匿名类
当然这里的方法也可以是构造器方法,此时的调用方式如下:
1 |
|
Stream API
介绍
Strream
API,所在的包为java.util.stream
,把真正的函数式编程风格引入到Java中,极大程度上提高Java程序员的生产力,写出高效率、干净、简洁的代码。Stream是Java8中处理集合的关键抽象概念,它可以指定我们希望对集合进行的操作,执行非常复杂的查找、过滤和映射等。还可以使用Stream
API来并行执行操作。简言之,Stream
API提供了一种高效且易于使用的处理数据的方式。
利用Stream,我们可以完成一系列的链式调用,最终得到想要的结果。(可以联想到Scala中的函数式编程)
Stream和Collection集合的区别:Collection是一种静态的内存数据接口,而Stream是有关计算的,前者主要面向内存,存储在内存中;后者主要面向CPU,通过CPU实现计算
- Stream自己不会存储元素
- Stream不会改变源对象,而是会返回一个持有结果的新Stream
- Stream操作是惰性执行的,需要结果的时候才会执行
Stream的操作一般分为以下步骤:
- 创建Stream,进行Stream的实例化
- 一系列中间操作
- 终止操作
需要注意的是,调用了终止操作之后,流就会关闭,不能再进行新的操作。强行调用操作会报错java.lang.IllegalStateException: stream has already been operated upon or closed
。我们需要生成新的流才能继续操作。
Stream实例化
Stream的实例化主要分为四种情况:
- 通过集合进行创建,调用集合的方法
- 通过数组进行创建,调用Arrays的静态方法
- 调用
Stream.of
方法 - 创建无限流
1 |
|
迭代生成:
1 |
|
直接生成:
1 |
|
中间操作
筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) |
从流中过滤某些元素 |
distinct() |
去重 |
limit(long maxSize) |
截断流,使其元素不超过给定数量 |
skip(long n) |
跳过前n个元素。如果流中元素不足n个,则返回一个空流 |
映射
方法 | 描述 |
---|---|
map(Function f) |
接收一个函数作为参数,该函数会应用到每个元素上,并将其映射成一个新的元素 |
mapToDouble(ToDoubleFunction f) |
接收一个函数作为参数,该函数会被应用到每个元素上,并产生一个新的DoubleStream |
mapToInt(ToIntFunction f) |
接收一个函数作为参数,该函数会被应用到每个元素上,并产生一个新的IntStream |
mapToLong(ToLongFunction f) |
接收一个函数作为参数,该函数会被应用到每个元素上,并产生一个新的LongStream |
flatMap(Function f) |
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流 |
排序
方法 | 描述 |
---|---|
sorted() |
产生一个新流,其中按照自然顺序排序 |
sorted(Comparator com) |
产生一个新流,其中按照比较器顺序排序 |
终止操作
匹配与查找
方法 | 描述 |
---|---|
allMatch(Predicate p) |
返回布尔值,检查是否所有元素都符合条件 |
anyMatch(Predicate p) |
返回布尔值,检查是否至少有一个元素符合条件 |
noneMatch(Precicate p) |
返回布尔值,检查是否所有元素都不符合条件 |
findFirst() |
返回第一个元素 |
findAny() |
返回任意一个元素 |
count() |
返回流中元素总数 |
max(Comparator c) |
返回流中最大值 |
min(Comparator c) |
返回流中最小值 |
forEach(Consumer c) |
内部迭代,对流中每个元素执行对应操作 |
规约
方法 | 描述 |
---|---|
reduce(T iden, BinaryOperator b) |
对流中元素进行规约,iden为初始值。返回T |
reduce(BinaryOperator b) |
对流中元素进行规约,返回Optional<T> |
收集
方法 | 描述 |
---|---|
collect(Collector c) |
将流转化为其他形式。接收一个Collector接口的实现,用于汇总流中的元素 |
Collector接口中方法的实现决定了如何对流执行收集(如收集到List、Set、Map)。另外在Collectors类中,提供了很多静态方法,可以方便地创建常见收集器实例。
Optional
Optional<T>
类是一个容器类,来自java.util.Optional
。它可以保存类型T的值,代表这个值存在;或者仅仅保存null,代表这个值不存在。原来使用null表示一个值不存在,现在使用Optional可以更好地表达这个概念,并且可以避免空指针异常。Optional中提供很多有用的方法,让我们不需要显式地进行空值检测
创建Optional类对象:
Optional.of(T t)
:创建一个Optional实例,t必须非空Optional.empty()
:创建一个空的Optional实例Optional.ofNullable(T t)
:创建一个Optional实例,t可以为null
判断Optional容器中是否包含对象:
boolean isPresent()
:判断是否包含对象void ifPresent(Consumer<? super T> consumer)
:如果有值,就执行Consumer接口的实现代码,其中该值作为consumer的参数
获取Optional容器的对象:
T get()
:如果调用对象包含值,返回该值,否则抛出异常T orElse(T other)
:如果有值则将其返回,否则返回指定的other对象T orElseGet(Supplier<? extends T> other)
:如果有值则将其返回,否则返回由Supplier接口实现提供的对象T orElseThrow(Supplier<? extends X> exceptionSupplier)
:如果有值则将其返回,否则抛出由Supplier接口实现提供的异常