Oracle JDK是基于Open JDK源代码的商业版本,要学习Java新技术可以去OpenJDK官网学习。
Lambda表达式介绍
-
匿名内部类存在的问题
-
new Thread(new Runnable() { @Override public void run() { // ... } }).start();
-
匿名内部类做了哪些事
- 定义了一个没有名字的类
- 实现了Runnable接口
- 创建了这个类的对象
-
其实我们最关注的是run方法和里面要执行的代码,使用匿名内部类语法是很冗余的
-
Lambda体现的是函数式编程思想,只需要将要执行的代码放到函数中
-
Lambda就是一个匿名函数,我们只需要将要执行的代码放到Lambda表达式中即可
-
-
体验Lambda表达式
-
new Thread(() -> { //... }).start();
-
好处:
- 简化匿名内部类,让代码更加精简
-
Lambda的标准格式
-
Lambda表达式是一个匿名函数,而函数相当于Java中的方法
-
(参数列表) -> { }
-
():参数列表
-
{}:方法体
-
->:没有实际含义,起到连接的作用
-
-
小结:
- 以后看到方法的参数是接口就可以考虑使用Lambda表达式
- 可以这么认为:Lambda表达式就是对接口中抽象方法的重写
- 不是所有匿名内部类都能用Lambda来替换
Lambda的实现原理
- 匿名内部类在编译的时候会形成一个.class文件
- Lambda在程序运行时会形成一个类
- 在类中新增一个方法,这个方法的方法体就是Lambda表达式中的代码
- 还会形成一个匿名内部类,实现接口,重写抽象方法
- 在接口的重写方法中会调用新生成的方法
- 在类中新增一个方法,这个方法的方法体就是Lambda表达式中的代码
- 理解:Lambda表达式就是对抽象方法的重写
Lambda省略格式
// 省略前
(int a) -> {
return new Person();
}
// 省略后
a -> new Person()
- 小括号内参数的类型可以省略
- 小括号内有且仅有一个参数,小括号可以省略
- 大括号内有且仅有一个语句,可以同时省略大括号、return关键字及分号
Lambda的前提条件
- 方法的参数或局部变量的类型必须为接口才能使用Lambda
- 接口中有且只有一个抽象方法
- 只有一个抽象方法的接口称为函数式接口,我们就能使用Lambda
- @FunctionalInterface:检测这个接口是否只有一个抽象方法
Lambda和匿名内部类对比
- 所需的类型不一样
- 匿名内部类:需要的类型可以是类、抽象类、接口
- Lambda:需要的类型必须是接口
- 抽象方法的数量不一样
- 匿名内部类:数量随意
- Lambda:只能有一个
- 实现原理不同
- 匿名内部类:编译后形成class文件
- Lambda:运行时动态生成class
JDK8接口新增的两个方法
-
JDK8以前
-
interface 接口名 { 静态常量; 抽象方法; }
-
-
JDK8对接口的增强,接口还可以有默认方法和静态方法
-
JDK8
-
interface 接口名 { 静态常量; 抽象方法; 默认方法; 静态方法; }
-
-
默认方法
-
- 因此JDK8时为接口新增了默认方法
- 接口中的默认方法实现类不必重写,可以直接使用,实现类也可以根据需要重写
-
默认方法的定义格式
-
interface 接口名 { 修饰符 default 返回值类型 方法名() { //... } }
-
-
默认方法的使用
- 实现类直接调用接口默认方法
- 实现类重写接口默认方法
-
-
静态方法
-
为了方便接口扩展,JDK8为接口新增了静态方法
-
静态方法的定义格式
-
interface 接口名 { 修饰符 static 返回值类型 方法名() { //... } }
-
-
静态方法的使用
- 接口静态方法实现类不会继承、不能重写?
- 使用:接口名.静态方法名()
-
-
区别
- 默认方法通过实例调用,静态方法通过接口名调用
- 默认方法可以被继承,实现类可以直接使用接口默认方法,也可以重写接口默认方法
- 静态方法不能被继承,实现类不能重写接口静态方法,只能通过接口名调用
常用内置函数式接口
-
在 java.util.function包中
-
Supplier接口
-
public interface Supplier<T> { T get(); }
-
-
Consumer接口
-
public interface Consumer<T> { void accept(T t); }
-
-
Function接口
-
public interface Function<T, R> { R apply(T t); }
-
-
Predicate接口
-
public interface Predicate<T> { boolean test(T t); }
-
方法引用格式
- 符号表示: ::
- 符号说明:双冒号为方法引用运算符,而它所在表达式被称为方法引用
- 应用场景:如果Lambda所要实现的方案,已经有其他方法存在相同方案,那么则可以使用方法引用
对象名::引用成员方法
- 注意事项
- 被引用的方法,参数要和接口中抽象方法的参数一样
- 当接口的抽象方法有返回值时,被引用的方法也必须有返回值
类名::引用静态方法
类名::引用实例方法
- 注意:
- 实际上会将第一个参数作为方法的调用者
- 类名:: 中的类名为第一个参数的类