Java学习:JDK8的新特性
一、Lambda表达式
1.概念
Lambda表达式是函数式接口中抽象方法的实现
注意:如果一个接口中,存在多个抽象方法,Lambda表达式无法实现!
2.语法
// Lambda表达式 - 方法 - 函数式接口抽象方法的实现
函数式接口 对象 = ([参数列表]) -> {方法体} ;
3.要点
-
使用空括号 () 表示没有参数
-
如果方法体只有一行代码,则大括号可以省略不写,如果有 return 语句,也可以省略不写
-
参数类型可以省略,参数类型可以由编译器根据上下文推断得出
-
(参数名称也可以不一样(不建议))
-
只有一个参数:可省略参数的括号(多个参数不能省略)
-
如果方法体有多行代码,则需要使用大括号,return不能省略
4.函数式接口
必须有且只有一个抽象方法的接口,称之为函数式接口。
一般,我们会结合 FunctionalInterface 注解显式声明函数式接口。
语法格式要求: 函数式接口除了有一个抽象方法外,也可以包含以下内容:
@FunctionalInterface
public inerface 接口名称 {
// 1.抽象方法(有且只有一个)
// 2.常量(0个或多个)
// 3.默认方法(0个或多个)
// 4.静态方法(0个或多个)
// 5.重新定义 Object 类的方法(0个或多个)
}
二、函数式编程
JDK提供的函数式接口
Java SE 7 中已经存在的函数式接口
- java.lang.Runnable
- java.util.concurrent.Callable
- java.security.PrivilegedAction
- java.util.Comparator
java.util.Comparator -- 比较器 int compare(T o1, T o2) : 比较两个数据的大小或顺序 o1 < o2 : 负整数 o1 = o2 : 0 o1 > o2 : 正整数
- java.io.FileFilter
- java.beans.PropertyChangeListener
Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口
Predicate<T>
——接收T
并返回boolean
Consumer<T>
——接收T
,不返回值Function<T, R>
——接收T
,返回R
Supplier<T>
——提供T
对象(例如工厂),不接收值
三、方法引用
1.概念
- 函数式接口的实现除了有Lambda表达式外,还有方法引用、构造器引用和数组引用的实现;
- 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个对象(实例);
- 方法引用是一种引用方法的轻量级语法
2.要点
如果已经存在一个实现了Lambda表达式的方法,那么就不需要编写Lambda表达式,而直接使用这个已经存在的方法,这称之为
方法引用
如果已经存在某个方法可以实现函数式接口中的抽象方法,那么我们就不需要定义Lambda表达式,而直接引用已经存在的方法即可。
3.语法
- 使用操作符 “::” 将类(或对象)与方法名分割开来(是已经实现好的方法名及其所在的类或对象);
- 可以看成左边的类或对象是调用者,右边的方法是被调用者。
以下是六种不同类型的方法引用:
四、Optional
1.概念
Java Optional是Java 8中引入的一种新的数据类型,它可以用来表示一个值存在或不存在的情况。它的设计目的是为了解决Java中空指针异常的问题。Integer、Double、Float…
Optional可以看作是一个包装类,它可以包装一个可能为空(null)的对象,然后通过一些方法来判断是否存在值,或者在不存在值的情况下提供一个默认值。
2.使用场景
- 避免空指针异常:在可能出现null值的情况下,使用Optional可以避免空指针异常的出现。
- 提高代码的可读性:使用Optional可以更加清晰地表达代码的意图。
- 链式调用:在多个方法调用中,使用Optional可以避免繁琐的判空操作,使代码更加简洁易懂。
- 简化代码逻辑:使用Optional可以避免复杂的if-else语句,使代码更加简洁易读。
五、Stream流式思想
1.概念
JDK8新特性,简单方便的对集合和数组进行处理。
Stream(流)是一个来自数据源的元素队列
2.特点
- Stream API 旨在让编码更高效率、干净、简洁
- 提供了一种函数式编程的方式来操作集合:API 方法 + Lambda表达式、方法引用
3.要点
方式 1:仅打印,不保留流
stream.filter(s -> s.getAge() > 18).forEach(System.out::println);
这种方式直接调用 forEach,不需要将结果赋值给变量
方式 2:保留过滤后的流
Stream<Student> studentStream = stream.filter(s -> s.getAge() > 18);
studentStream.forEach(System.out::println);
这种方式先通过 filter 创建一个新的流,并将其赋值给 studentStream,然后对这个流调用 forEach。
总结
Stream 的链式调用需要区分中间操作和终端操作。