匿名内部类的格式:

1
2
3
new 父类或接口() {
重写的方法;
}
在匿名内部类中,有很多内容都是冗余的。

比如在使用匿名内部类实现多线程的代码中。

  • 因为 Thread 构造方法中需要传递 Runnable 接口类型的参数,所以我们不得不 new Runnable。
  • 因为要重写 Runnable 中的 run 方法,所以不得不写了public void run。

整个匿名内部类中最关键的东西是方法,方法中最关键的有前中后三点。

  • 前:参数。
  • 中:方法体
  • 后:返回值

最好的情况是只关注匿名内部类中最核心的这些内容(方法参数,方法体,返回值)如果使用Lambda表达式,可以只关注最核心的内容,Lambda 表达式是匿名内部类的简化写法。

Lambda 属于函数式编程思想。

  • 面向对象思想:怎么做。
  • 函数式编程思想:做什么。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Demo01Inner {
public static void main(String[] args) {
//使用匿名内部类的方式实现多线程。
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行了");
}
}).start();

//使用Lambda表达式实现多线程
new Thread(() -> System.out.println(Thread.currentThread().getName() + "执行了")).start();
}
}

匿名内部类可以省去单独创建 .java 文件的操作。但是匿名内部类也是有缺点的,写法太冗余了,里面有很多多余的部分。

匿名内部类也有简化写法,匿名内部类的简化写法是 Lambda 表达式匿名内部类中最关键的内容是方法的参数,方法体,以及返回值,而在 Lambda 表达式中,关注的就是这三个关键的东西。

Lambda 表达式的标准格式:

1
2
3
4
(参数类型 参数名) -> {
方法体;
return 返回值;
}

格式解释:

  • 小括号中的参数和之前方法的参数写法一样,可以写任意个参数,如果多个参数,要使用逗号隔开。
  • -> 是一个运算符,表示指向性动作。
  • 大括号中的方法体以及 return 返回值的写法和之前方法的大括号中的写法一样。

Lambda 表达式是函数式编程思想。

函数式编程:可推导,就是可省略。
  • 因为在 Thread 构造方法中需要 Runnable 类型的参数,所以可以省略 new Runnable。
  • 因为 Runnable 中的只有一个抽象方法 run,所以重写的必然是这个 run 方法,所以可以省略 run 方法的声明部分(public void run)

Lambda 表达式可以省略面向对象中的一些条条框框,让我们只关注最核心的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Demo02Lambda {
public static void main(String[] args) {
//实现多线程(单独创建.java)
new Thread(new Task()).start();
//使用匿名内部类的方式实现多线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行了");
}
}).start();
//使用Lambda表达式完成多线程
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "执行了");
}).start();
}
}

匿名内部类与 Lambda 函数比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Demo03Collections {
public static void main(String[] args) {
//创建集合
List<Student> list = new ArrayList<>();
//添加元素
list.add(new Student("嫐", 20));
list.add(new Student("嬲", 18));
list.add(new Student("挊", 22));
//使用比较器排序对集合中的学生对象根据年龄升序排序
//Collections.sort(list, new Rule());

//使用匿名内部类
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});

//使用Lambda表达式
Collections.sort(list, (Student o1, Student o2) -> {
return o1.getAge() - o2.getAge();
});

Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());

System.out.println(list);

}
}

Lambda 格式

Lambda 表达式的标准格式:
1
2
3
4
(参数类型 参数名) -> {
方法体;
return 返回值;
}
Lambda 表达式的省略规则:
  • \1. 小括号中的参数类型可以省略。
  • \2. 如果小括号中只有一个参数,那么可以省略小括号。
  • \3. 如果大括号中只有一条语句,那么可以省略大括号,return,分号。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Demo04SimpleLambda {
//定义方法,使用接口当做参数
public static void method(MyInterface m) {
m.printStr("hello");
}

public static void main(String[] args) {
//调用method方法,参数传递MyInterface实现类对象
method(new MyInterface() {
@Override
public void printStr(String str) {
System.out.println(str);
}
});
//使用Lambda表达式的标准格式。
method((String str) -> {
System.out.println(str);
});

//1. 小括号中的参数类型可以省略。
method((str) -> {
System.out.println(str);
});
//2. 如果小括号中只有一个参数,那么可以省略小括号。
method(str -> {
System.out.println(str);
});
//3. 如果大括号中只有一条语句,那么可以省略大括号,return,分号。
method(str -> System.out.println(str));
}
}

Lambda 使用条件

Lambda 表达式的使用前提:
  • 必须有接口(不能是抽象类),接口中有且仅有一个需要被重写的抽象方法。
  • 必须支持上下文推导,要能够推导出来 Lambda 表达式表示的是哪个接口中的内容。

可以使用接口当做参数,然后传递 Lambda 表达式(常用),也可以将 Lambda 表达式赋值给一个接口类型的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Demo05BeforeLambda {
//使用接口当做参数
public static void method(MyInterface m) {//m = s -> System.out.println(s)
m.printStr("HELLO");
}

public static void main(String[] args) {
//使用接口当做参数,然后传递Lambda表达式。
//method(s -> System.out.println(s));

//使用匿名内部类方式创建对象
/*
MyInterface m = new MyInterface() {
@Override
public void printStr(String str) {
System.out.println(str);
}
};
*/

MyInterface m = str -> System.out.println(str);
m.printStr("Hello");
}
}