java8新特性-lambda表达式

写在前面

这篇lambda的文章,应该放在java8新特性的第一篇来介绍的,oracle发布java8时表示,JDK8包括自java平台1996年推出以来最重大的Java编程模型升级。而lambda是java8中最重要的内容。

1.lambda是什么

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。–via [百度百科]

lambda演算,支持函数作为入参输入和输出值。

jdk8完成了对lambda的支持,也就意味着,java这门编程语言,开始支持函数式编程。

2.jdk8的lambda用在什么地方

讲lambda之前,必须要引入一个新的概念功能接口(functional interface),lambda表达式,就是用来实现功能接口的

功能接口

一个接口,如果他有且只有一个抽象方法,那么他就是一个功能接口。为此,jdk8中还新加入了@FunctionalInterface这个注解,如果一个接口是功能接口的话,你应该为这个接口使用这个注解来标识。不过这不是强制的,即使你的接口上没有这个注解,但是只包含一个抽象方法,编译器也会认为你的接口是功能接口。诸如Comparable<T>,ActionListener接口虽然没有@FunctionalInterface注解,但依然是功能接口

3.lambda表达式的语法

下面这段代码,是典型的lambda表达式

1
2
3
(int i,String str) -> {System.out.println(str);
System.out.println(str);
}

3.1(int i,String str)是参数列表,其中类型可以省略,写成(i,str)编译器会推断目标类型

3.2->箭头标识,你可以理解为关键字,其前面是参数列表,后面是对功能接口的实现

3.3{System.out.println(str);System.out.println(str);}这部分相当于普通java方法的方法体,如果是多行代码,必须以{}花括号包裹起来,如果是单行代码可以省略括号。

4.lambda in action

这一节中,分别以传统方式和新的lambda表达式对比,来看lambda到底为我们带来了哪些东西

4.1 声明一个功能接口

只有一个抽象方法的接口,即是功能接口。此外还有一个接口默认方法,前文已介绍过,这里必须要说明一下,在oracle的官方文档中,接口默认方法属于lambda表达式的一部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package me.momotime.java8.lambda;
/**
* 检查Student是否符合规则
* @author momo
*/
@FunctionalInterface
public interface StudentFilter {
/**
* 检查是否符合规则
* @param s 学生
* @return 满足条件返回true
*/
boolean test(Student s);
/**
* 接口默认方法
* @return 年龄大于0返回true
*/
default boolean test2(Student s) {
return s.getAge() > 0;
}
}

Student类代码

1
2
3
4
5
6
7
package me.momotime.java8.lambda;
public class Student {
private String name;
private int age;
private String gender;
//省略getter setter等代码
}

4.2 传统方式-使用内部类

下面的测试类中,可以看到printStudent(List<Student> list, StudentFilter filter)这个方法,第二个参数的类型,是上面声明的功能接口。在main函数中调用的话,传统方式,是使用一个内部类或者内部匿名类,里面重写接口的实现,这里入参还是一个对象。

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
32
33
34
35
package me.momotime.java8.lambda;
import java.util.ArrayList;
import java.util.List;
/**
* @author momo
*/
public class TestStudent {
public static void main(String args[]) {
Student s1 = new Student("aa", 12, "male");
Student s2 = new Student("bb", 18, "female");
Student s3 = new Student("cc", -2, "female");
List<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
// 传统方式
printStudent(list, new StudentFilter() {
@Override
public boolean test(Student s) {
//如果年龄大于15返回true
return s.getAge() > 15;
}
});
}
/**
* 打印输出满足条件的学生
*/
static void printStudent(List<Student> list, StudentFilter filter) {
for (Student student : list) {
if (filter.test(student)) {
System.out.println("符合条件的同学是: " + student.getName());
}
}
}
}

4.3 使用lambda表达式

lambda写法

1
printStudent(list, (Student s) -> s.getAge() > 15);

是的,你没有看错。上面这行lambda表达式写法和上面传统方式5行代码实现的功能是完全一样的。

第二个参数本应该是StudentFilter类型的对象,而我们这里的入参是一个函数,编译器在遇到lambda表达式的时候,会自动推断lambda表达式的参数列表,并且将->箭头后面的函数体推断为StudentFilter.test(Student s)方法,因为功能函数只有一个抽象方法,而lambda函数体就是实现的这个抽象方法。

当然我们这个函数体只有一行代码,所以省略了{}花括号。

4.4 使用方法引用

第二个参数可以使用方法引用,方法引用在之前的文章中已经介绍过了,这里主要是要说明,方法引用,也是lambda的一部分,

5.随便扯一点

lambda我们带来了函数式编程的特性;减少了代码量,代码更加易读;lambda能充分利用多核cpu的能力。这些足以证明jdk8为java带来的活力。

其他语言可能很早就支持lambda了,java迟了点,但终究是来了