目录
一:使用匿名内部类存在的问题
Lambda表达式写法,代码如下:
二:Lambda的标准格式
三:Lambda的实现原理
四:Lambda省略格式
五:Lambda的前提条件
六:函数式接口
七:Lambda和匿名内部类对比
一:使用匿名内部类存在的问题
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程执行代码啦");
}
}).start();
由于面向对象的语法要求,首先创建一个 Runnable 接口的匿名内部类对象来指定线程要执行的任务内容,再将其交给一个线程来启动。
匿名内部类做了哪些事情:
1.定义了一个没有名字的类
2.这个类实现了Runnable接口
3.创建了这个类的对象(new)
- Thread 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心
- 为了指定 run 的方法体,不得不需要 Runnable 接口的实现类
- 为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类
- 必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错
- 而实际上,似乎只有方法体才是关键所在。
感觉代码很熟悉,但是我们最关注的是run方法和里面要执行的代码.,但是由于面向对象的特征,我们不得不弄一个类出来,去实现Runnable接口,重写run方法,new这个对象出来,可以体会到使用匿名内部类语法是很冗余的,因此,JDK 8根据这个问题提出一个新特性:Lambda表达式
Lambda表达式体现的是函数式编程思想,只需要将要执行的代码放到函数中(函数就是类中的方法),Lambda就是一个匿名函数,可以理解为一段可以传递的代码, 我们只需要将要执行的代码放到Lambda表达式中即可
Lambda表达式写法,代码如下:
public class Demo01LambdaIntro {
public static void main(String[] args) {
new Thread(() -> System.out.println("新线程任务执行!")).start(); // 启动线程
}
}
Lambda表达式的好处: 可以简化匿名内部类,让代码更加精简
二:Lambda的标准格式
(参数类型 参数名称) -> {
代码体;
}
- (参数类型 参数名称):参数列表
- {代码体;}:方法体
- -> :箭头,分隔参数列表和方法体,起到连接作用
public void run() {
System.out.println("aa");
}
() -> System.out.println("bb!")
- 练习无参数无返回值的Lambda
interface Swimmable {
public abstract void swimming();
}
public class Demo02LambdaUse {
public static void main(String[] args) {
//传统方式
goSwimming(new Swimmable() {
@Override
public void swimming() {
System.out.println("凤姐 自由泳.");
}
});
//Lambda表达式
goSwimming(() -> {
System.out.println("如花 蛙泳");
});
}
// 小结:以后我们看到方法的参数是接口就可以考虑使用Lambda表达式
// Lambda表达式相当于是对接口抽象方法的重写
// 练习无参数无返回值的Lambda
public static void goSwimming(Swimmable s) {
s.swimming();
}
}
- 练习有参数有返回值的Lambda
定义一个接口,并定义一个抽象方法,带有参数
interface Smokeable {
public abstract int smoking(String name);
}
goSmoking(new Smokeable() {
@Override
public void smoking() {
System.out.println("有一根"+name+"的烟");
return 5;
}
});
goSmoking((String name) ->{
System.out.println("Lambda 有"+name+"的烟");
return 6;
});
// 练习有参数有返回值的Lambda
public static void goSmoking(Smokeable s) {
int i= s.smoking("China made");
System.out.println(i);
}
- public abstract int compare(T o1, T o2);
public class Person {
private String name;
private int age;
private int height;
// 省略其他
}
// 练习有参数有返回值的Lambda
public class Demo03LambdaParam {
public static void main(String[] args) {
ArrayList<Person> persons = new ArrayList<>();
persons.add(new Person("刘德华", 58, 174));
persons.add(new Person("张学友", 58, 176));
persons.add(new Person("刘德华", 54, 171));
persons.add(new Person("黎明", 53, 178));
// 对集合中的数据进行排序
/*Collections.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge(); // 升序排序
}
});*/
Collections.sort(persons, (Person o1, Person o2) -> {
return o2.getAge() - o1.getAge(); // 降序
});
for (Person person : persons) {
System.out.println(person);
}
System.out.println("-----------");
persons.forEach((t) -> {
System.out.println(t);
});
}
}
(参数列表) -> {
方法体;
}
三:Lambda的实现原理
@FunctionalInterface
interface Swimmable {
public abstract void swimming();
}
public class Demo04LambdaImpl {
public static void main(String[] args) {
goSwimming(new Swimmable() {
@Override
public void swimming() {
System.out.println("使用匿名内部类实现游泳");
}
});
}
public static void goSwimming(Swimmable swimmable) {
swimmable.swimming();
}
}
使用XJad反编译这个类,得到如下代码:
package com.tangyuan.demo01lambda;
import java.io.PrintStream;
// Referenced classes of package com.itheima.demo01lambda:
// Swimmable, Demo04LambdaImpl
static class Demo04LambdaImpl$1 implements Swimmable {
public void swimming()
{
System.out.println("使用匿名内部类实现游泳");
}
Demo04LambdaImpl$1() {
}
}
public class Demo04LambdaImpl {
public static void main(String[] args) {
goSwimming(() -> {
System.out.println("Lambda游泳");
});
}
public static void goSwimming(Swimmable swimmable) {
swimmable.swimming();
}
}
javap -c -p 文件名.class
-c:表示对代码进行反汇编
-p:显示所有类和成员
C:\Users\>javap -c -p Demo04LambdaImpl.class
Compiled from "Demo04LambdaImpl.java"
public class com.itheima.demo01lambda.Demo04LambdaImpl {
public com.tangyuan.demo01lambda.Demo04LambdaImpl();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:swimming:
()Lcom/tangyuan/demo01lambda/Swimmable;
5: invokestatic #3 // Method goSwimming:
(Lcom/tangyuan/demo01lambda/Swimmable;)V
8: return
public static void goSwimming(com.itheima.demo01lambda.Swimmable);
Code:
0: aload_0
1: invokeinterface #4, 1 // InterfaceMethod
com/tangyuan/demo01lambda/Swimmable.swimming:()V
6: return
private static void lambda$main$0();
Code:
0: getstatic #5 // Field
java/lang/System.out:Ljava/io/PrintStream;
3: ldc #6 // String Lambda游泳
5: invokevirtual #7 // Method java/io/PrintStream.println:
(Ljava/lang/String;)V
8: return
}
可以确认 lambda$main$0 里面放的就是Lambda中的内容,我们可以这么理解 lambda$main$0 方法:
public class Demo04LambdaImpl {
public static void main(String[] args) {
...
}
private static void lambda$main$0() {
System.out.println("Lambda游泳");
}
}
java -Djdk.internal.lambda.dumpProxyClasses 要运行的包名.类名
C:\Users\>java -Djdk.internal.lambda.dumpProxyClasses
com.tangyuan.demo01lambda.Demo04LambdaImpl
Lambda游泳
执行完毕,可以看到生成一个新的类,效果如下:
反编译 Demo04LambdaImpl$$Lambda$1.class 这个字节码文件,内容如下:
// Referenced classes of package com.tnagyuan.demo01lambda:
// Swimmable, Demo04LambdaImpl
final class Demo04LambdaImpl$$Lambda$1 implements Swimmable {
public void swimming()
{
Demo04LambdaImpl.lambda$main$0();
}
private Demo04LambdaImpl$$Lambda$1()
{
}
}
public class Demo04LambdaImpl {
public static void main(String[] args) {
goSwimming(new Swimmable() {
public void swimming() {
Demo04LambdaImpl.lambda$main$0();
}
});
}
private static void lambda$main$0() {
System.out.println("Lambda表达式游泳");
}
public static void goSwimming(Swimmable swimmable) {
swimmable.swimming();
}
}
四:Lambda省略格式
(int a) -> {
return new Person();
}
a -> new Person()
案例如下:
public static void main(String[] args) {
ArrayList<Person> persons = new ArrayList<>();
persons.add(new Person("刘德华", 58, 174));
persons.add(new Person("张学友", 58, 176));
persons.add(new Person("刘德华", 54, 171));
persons.add(new Person("黎明", 53, 178));
----------------------------省略前--------------
Collections.sort(persons, (o1, o2) -> {
return o1.getAge() - o2.getAge();
});
for (Person person : persons) {
System.out.println(person);
}
---------------------------------省略后---------------------------
Collections.sort(persons, (o1, o2) -> o2.getAge() - o1.getAge());
persons.forEach(t -> System.out.println(t));
}
五:Lambda的前提条件
public interface Flyable {
public abstract void flying();
}
public class Demo06LambdaCondition {
public static void main(String[] args) {
// 方法的参数或局部变量类型必须为接口才能使用Lambda
test(() -> {
});
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("aa");
}
};
Flyable f = () -> {
System.out.println("我会飞啦");
};
}
public static void test(Flyable a) {
new Person() {
};
}
}
// 只有一个抽象方法的接口称为函数式接口,我们就能使用Lambda
@FunctionalInterface // 检测这个接口是不是只有一个抽象方法
interface Flyable {
// 接口中有且仅有一个抽象方法
public abstract void eat();
// public abstract void eat2();
}
六:函数式接口
@FunctionalInterface
public interface Operator {
void myMethod();
}