lambda表达式
什么是lambda表达式
Java 是面向对象的语言,一切皆对象,Java中的方法不能够单独存在,将方法作为参数传入需要用到匿名内部类,为了解决这一问题,Java8增加了新特性,即Lambda表达式。
lambda表达式实现原理
函数式接口
可以通过Lambda表达式来创建该接口的对象
@FunctionalInterface
interface IFunctionTest<T> {
public void print(T x);
}
函数式接口只允许声明一个抽象方法
@FunctionalInterface
interface IFunctionTest<T> {
public void print(T x);
default void print1(T x){};
static void print2() {};
@Override
boolean equals(Object obj);
}
额外声明default,static或者是override方法是可以的。
Lambda表达式的运行原理又是怎样的呢?
- 首先,在类编译时,会生成一个私有静态方法+一个内部类;
- 内部类实现函数式接口,在实现接口的方法中,会调用编译器生成的静态方法;
- 在使用lambda表达式的地方,通过传递内部类实例,来调用函数式接口方法。
以上可以通过反编译代码来验证,具体可参考https://www.cnblogs.com/WJ5888/p/4667086.html
lambda表达式使用场景
现有一Person类
package lambda.usage;
import java.time.LocalDate;
public class Person {
public enum Sex {
MALE, FEMALE
}
/**
* 字段说明省略
*/
String name;
LocalDate birthday;
Sex gender;
String email;
}
现有List<Person> ,需求是从List中筛选合适的Person。
在没有lambda之前有以下几种解决方案
- 直接写方法
- 实现接口
- 匿名内部类
方案1,2,3都可以实现需求,但是如果使用方案1,2要实现多个筛选条件,就要实现多个方法,那么有没有更简洁的方式呢,过去我们用匿名内部类实现,例如我们想筛选出女性,代码如下。
interface PersonFilter<T>{
boolean filter(T t);
}
public static boolean filter(Person p, PersonFilter<Person> PersonFilter) {
return PersonFilter.filter(p);
}
//筛选女性
List<Person> females = new ArrayList<>();
for (Person person : people) {
if (filter(person, new PersonFilter<Person>() {
@Override
public boolean filter(Person person) {
return Person.Sex.FEMALE.equals(person.getGender());
}
})) {
females.add(person);
}
}
可以看出,使用匿名内部类可以解决以上问题,但是程序看起来并不简洁,那么有没有更好的方案呢?
在引入lambda表达式后,我们可以这样做。
for (Person person : people) {
if (filter(person, p -> p.getGender().equals(Person.Sex.FEMALE))){
females.add(person);
}
}
除此之外,PersonFilter是一个非常简单的接口。它只包含了唯一的抽象方法因而它是一个函数接口。该方法接收一个参数并返回一个boolean值。该方法是如此的简单以至于没有必要在应用程序中进行定义。 因此,JDK中的java.util.function包中定义了很多标准的函数接口。
例如,我们可以使用Predicate接口来代替PersonFilter
public static boolean filter(Person p, Predicate<Person> PersonFilter) {
return PersonFilter.test(p);
}
那么,为什么可以这样用呢?原因很简单,这是Predicate接口中test()的源码。
boolean test(T t);
同理,如果想传入一个返回void方法,可以使用Consumer<T>接口的accept()方法。如果想传入一个带有返回值的方法,可以使用Function<T, R>接口的apply(T t)方法。
还可以使用泛型,下面代码的功能是打印女同志的姓名
public static <X, Y> void processPerson(
Iterable<X> source,
Predicate<X> tester,
Function<X, Y> mapper,
Consumer<Y> block) {
for(X x : source) {
if (tester.test(x)) {
Y data = mapper.apply(x);
block.accept(data);
}
}
}
processPerson(
people,
p -> Person.Sex.FEMALE.equals(p.getGender()),
p -> p.getName(),
name -> System.out.println(name)
);
除此之外,还可以使用聚集操作来实现此功能,代码如下。
people.stream()
.filter(person -> Person.Sex.FEMALE.equals(person.getGender()))
.map(person -> person.getName())
.forEach(name -> System.out.println(name));
lambda表达式语法
lambda表达式有以下几个部分组成
- 形参列表:参数类型可省略,如果只有一个参数括号也可省略。
- 箭头:
->
- 主体:{}, 如果写return,花括号不可省
访问外围作用域中的局部变量
使用this关键字
参考自:
http://tutorials.jenkov.com/java/lambda-expressions.html
https://blog.csdn.net/code_for_fun/article/details/42169993