前述#
Lambda表达式是 Java 8 的新特性。许多语言都有 Lambda 的特性。
因此使用的 Java 环境一定要 8 以上的环境。
Lambda#
到底什么是 Lambda 表达式呢?
Lambda 表达式,也可称为闭包。Lambda 允许把函数作为一个方法的参数直接传递到方法中去。可以让我们不用费神去给函数起名。但是 Lambda 也只适合于简单的函数,对于复杂的函数,写成 Lambda 的形式反而会让人更加看不懂。
实例#
接下来用一个实例慢慢导入 Lambda,要完成的是一个判断Person的id是否大于90的功能
首先创建一个Person类,包含 id 属性
复制代码
1 package person;
2
3 /**
4 * Person类
5 * @author jyroy
6 *
7 */
8 public class Person {
9 @SuppressWarnings("unused")
10 public int id;
11
12 public Person() {
13
14 }
15
16 public Person(int id) {
17 this.id = id;
18 }
19
20 @Override
21 public String toString() {
22 return "Person [id=" + id + "]";
23 }
24
25 }
复制代码
普通方法#
用普通方法,在 for 循环中通过 if 进行条件判断 if(person.id>90)
复制代码
1 package normal;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import lambda.Check;
8 import person.Person;
9
10 public class TestLambda {
11 @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
12 public static void main(String[] args) {
13 Random r = new Random(); //随机生成100个数
14 List
lists = new ArrayList();
15 for(int i=0;i<100;i++) {
16 lists.add(new Person(r.nextInt(100)));
17 }
18 //使用 Lambda 筛选出大于90的数据
19 judge(lists);
20
21 }
22 @SuppressWarnings("rawtypes")
23 private static void judge(List lists) {
24 for(Person person:lists) {
25 if(person.id>90) { //判断是否大于90
26 System.out.println(person);
27 }
28 }
29 }
30 }
复制代码
结果
匿名类方法#
创建一个匿名类,通过匿名类来实现这个判断 id 大于90的功能。
首先提供匿名类需要的接口,用于创建一个判断的类
复制代码
1 package anonymity;
2
3 import person.Person;
4
5 public interface PersonCheck {
6 public boolean test(Person person);
7 }
复制代码
通过匿名类实现接口
复制代码
1 //使用 匿名类的方式 筛选出大于90的数据
2 PersonCheck personCheck = new PersonCheck() {
3 @Override
4 public boolean test(Person person) {
5 return person.id>90;
6 }
7 };
复制代码
实现之后,就可以在judge函数中调用personCheck实例的test函数进行处理
复制代码
1 package anonymity;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import lambda.Check;
8 import person.Person;
9
10 /**
11 * 匿名类方式
12 * @author jyroy
13 *
14 */
15 public class TestLambda {
16 @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
17 public static void main(String[] args) {
18 Random r = new Random();
19 List lists = new ArrayList();
20 for(int i=0;i<100;i++) {
21 lists.add(new Person(r.nextInt(100)));
22 }
23
24 //使用 匿名类的方式 筛选出大于90的数据
25 PersonCheck personCheck = new PersonCheck() {
26 @Override
27 public boolean test(Person person) {
28 return person.id>90;
29 }
30 };
31
32 judge(lists, personCheck);
33
34 }
35 @SuppressWarnings("rawtypes")
36 private static void judge(List lists, PersonCheck personCheck) {
37 for(Person person:lists) {
38 if(personCheck.test(person)) {
39 System.out.println(person);
40 }
41 }
42 }
43 }
复制代码
结果
Lambda方式#
接下来就是Lambda方式了
先上 Lambda表达式的写法,运行过程序之后再做总结
1 person->person.id>90
这便是一个Lambda表达式的形式,先记住这个形式,这个形式就是判断 person.id>90。
复制代码
1 package lambda;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import anonymity.PersonCheck;
8 import person.Person;
9
10 /**
11 * Lambda表达式
12 * @author jyroy
13 *
14 */
15 public class TestLambda {
16
17 @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
18 public static void main(String[] args) {
19 Random r = new Random();
20 List lists = new ArrayList();
21 for(int i=0;i<100;i++) {
22 lists.add(new Person(r.nextInt(100)));
23 }
24 //使用 Lambda 筛选出大于90的数据
25 filter(lists, person -> person.id > 90);
26
27 }
28 @SuppressWarnings("rawtypes")
29 private static void filter(List lists, PersonCheck personCheck) {
30 for(Person person:lists) {
31 if(personCheck.test(person)) {
32 System.out.println(person);
33 }
34 }
35 }
36 }
复制代码
结果
实现了同样的效果
总结#
上面的程序中使用了 Lambda表达式,完成了判断的功能,而且相比匿名类的写法要简单非常多,使用 Lambda 表达式可以使代码变的更加简洁紧凑。
Lambda 表达式的语法格式:
复制代码
1 (parameters) -> expression
2 或
3 (parameters) ->{ statements; }
复制代码
以下是lambda表达式的重要特征:
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
简单的例子
复制代码
1 // 1. 不需要参数,返回值为 5
2 () -> 5
3
4 // 2. 接收一个参数(数字类型),返回其2倍的值
5 x -> 2 * x
6
7 // 3. 接受2个参数(数字),并返回他们的差值
8 (x, y) -> x – y
9
10 // 4. 接收2个int型整数,返回他们的和
11 (int x, int y) -> x + y
12
13 // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
14 (String s) -> System.out.print(s)
复制代码
现在就可以解释上面的实例中的 Lambda表达式 的含义
person->person.id>90
即接收一个person参数,并返回大于person.id>90的数据
Lambda方法引用#
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。
可以看作是lambda的一种快捷写法,显式的指定方法的名称更具可读性。格式:目标引用+分隔符::+方法,例如,Dog::getAge就是引用了Dog类中定义的方法getAge。
注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。
Lambda方法引用包含一下四种:
静态方法引用
对象方法引用
类成员方法引用
构造方法引用
静态方法引用#
首先需要有一个静态方法
复制代码
1 public static boolean test(Person person) {
2 return person.id>90 && person.id<95;
3 }
复制代码
在Lambda表达式中调用这个静态方法,因为是静态方法可以不用创建对象,所以直接用类名进行调用
复制代码
1 judge(lists, person -> TestLambda.test(person));
复制代码
利用方法引用调用静态方法的形式
复制代码
1 judge(lists, TestLambda::test);
复制代码
主程序为
复制代码
1 package references;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import anonymity.PersonCheck;
8 import person.Person;
9
10 /**
11 * Lambda表达式
12 * @author jyroy
13 *
14 */
15 public class TestLambda {
16
17 @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
18 public static void main(String[] args) {
19 Random r = new Random();
20 List lists = new ArrayList();
21 for(int i=0;i<100;i++) {
22 lists.add(new Person(r.nextInt(100)));
23 }
24 //使用 Lambda 筛选出大于90的数据
25 judge(lists, person -> person.id < 10);
26
27 //在Lambda表达式中使用静态方法
28 judge(lists, person -> TestLambda.test(person));
29
30 //直接使用静态方法
31 judge(lists, TestLambda::test);
32
33 }
34
35 public static boolean test(Person person) {
36 return person.id>90 && person.id<95;
37 }
38
39 @SuppressWarnings("rawtypes")
40 private static void judge(List lists, PersonCheck personCheck) {
41 for(Person person:lists) {
42 if(personCheck.test(person)) {
43 System.out.println(person);
44 }
45 }
46 }
47 }
复制代码
对象方法引用#
和静态方法相似,,但是在传递方法的时候,因为不是静态方法,所以必须要利用对象进行传送
复制代码
1 package references;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import anonymity.PersonCheck;
8 import person.Person;
9
10 /**
11 * Lambda表达式
12 * @author jyroy
13 *
14 */
15 public class TestLambda {
16
17 @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
18 public static void main(String[] args) {
19 Random r = new Random();
20 List lists = new ArrayList();
21 for(int i=0;i<100;i++) {
22 lists.add(new Person(r.nextInt(100)));
23 }
24
25 //使用引用对象方法
26 TestLambda testLambda = new TestLambda();
27 judge(lists, testLambda::test2);
28
29 }
30
31 public boolean test2(Person person) {
32 return person.id>90 && person.id<95;
33 }
34
35 @SuppressWarnings("rawtypes")
36 private static void judge(List lists, PersonCheck personCheck) {
37 for(Person person:lists) {
38 if(personCheck.test(person)) {
39 System.out.println(person);
40 }
41 }
42 }
43 }
复制代码
类成员方法引用#
Person类要添加一个成员方法,才能够进行成员方法的引用
复制代码
1 public boolean test3() {
2 return this.id>90 && this.id<95;
3 }
复制代码
在Lambda表达式中使用 test3方法
复制代码
1 judge(lists, person -> person.test3());
复制代码
利用方法引用的写法为
1 judge(lists, Person::test3);
主程序为
复制代码
1 package references;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import anonymity.PersonCheck;
8 import person.Person;
9
10 /**
11 * Lambda表达式
12 * @author jyroy
13 *
14 */
15 public class TestLambda {
16
17 @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
18 public static void main(String[] args) {
19 Random r = new Random();
20 List lists = new ArrayList();
21 for(int i=0;i<100;i++) {
22 lists.add(new Person(r.nextInt(100)));
23 }
24
25
26 //使用类成员方法
27 judge(lists, person -> person.test3());
28
29 //可改写为
30 judge(lists, Person::test3);
31
32
33 }
34
35 public static boolean test(Person person) {
36 return person.id>90 && person.id<95;
37 }
38
39 public boolean test2(Person person) {
40 return person.id>90 && person.id<95;
41 }
42
43 @SuppressWarnings("rawtypes")
44 private static void judge(List lists, PersonCheck personCheck) {
45 for(Person person:lists) {
46 if(personCheck.test(person)) {
47 System.out.println(person);
48 }
49 }
50 }
51 }
复制代码
构造方法引用#
需要有返回一个对象的方法
构造方法引用形式为
复制代码
1 ArrayList::new
2 Person::new
复制代码
复制代码
1 package lambda;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.function.Supplier;
6
7 public class TestLambda {
8 public static void main(String[] args) {
9 Supplier s = new Supplier() {
10 public List get() {
11 return new ArrayList();
12 }
13 };
14 //引用构造器
15 List list3 = getList(ArrayList::new);
16
17 }
18
19 public static List getList(Supplier s){
20 return s.get();
21 }
复制代码
聚合操作#
引入实例#
在上面的程序中,遍历输出数据利用的是for循环的方式
复制代码
1 for(Person person:lists) {
2 if(personCheck.test(person)) {
3 System.out.println(person);
4 }
5 }
复制代码
我们可以利用聚合操作来进行数据的输出
复制代码
1 lists
2 .stream()
3 .filter(person -> person.id>95)
4 .forEach(person -> System.out.println(person.id));
复制代码
主程序为
复制代码
1 package normal;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Random;
6
7 import lambda.Check;
8 import person.Person;
9
10 public class TestLambda {
11 @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
12 public static void main(String[] args) {
13 Random r = new Random();
14 List lists = new ArrayList();
15 for(int i=0;i<100;i++) {
16 lists.add(new Person(r.nextInt(100)));
17 }
18 System.out.println("使用传统方式----");
19 for(Person person:lists) {
20 if(person.id>90) {
21 System.out.println(person);
22 }
23 }
24 System.out.println("聚合操作方式");
25 lists
26 .stream()
27 .filter(person -> person.id>95)
28 .forEach(person -> System.out.println(person.id));
29 }
30 }
复制代码
结果
Stream和管道#
我们对应上面的代码,可以看出,聚合操作分为三步
生成
操作、变换(可以多次)
消耗(只有一次)
当然我们还要知道stream和管道的概念
Stream:Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到,前面处理的结果。注意:这个Stream和I/O中的InputStream,OutputStream是不一样的概念。
管道:指的是一系列的聚合操作。
管道又分3个部分:管道源、中间操作、结束操作
管道源:在这个例子里,源是一个List,可以用 .stream() 方法切换成管道源。但是数组没有stream() 方法,需要用 Arrays.stream(hs) 或者 Stream.of(hs)
复制代码
1 package lambda;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Random;
8
9 import charactor.Hero;
10
11 public class TestAggregate {
12
13 public static void main(String[] args) {
14 Random r = new Random();
15 List heros = new ArrayList();
16 for (int i = 0; i < 5; i++) {
17 heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
18 }
19 //管道源是集合
20 heros
21 .stream()
22 .forEach(h->System.out.println(h.name));
23
24 //管道源是数组
25 Hero hs[] = heros.toArray(new Hero[heros.size()]);
26 Arrays.stream(hs)
27 .forEach(h->System.out.println(h.name));
28
29 }
30 }
复制代码
中间操作: 每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒