Lambda 表达式
简介
Java8新特性,从本质上讲,是一个匿名函数。可以使用这个匿名函数,实现接口中的方法
。对接口进行非常简洁的实现,从而简化代码。
简化接口的实现
使用场景
关于接口的实现,可以有很多种方式来实现。例如:设计接口的实现类、使用匿名内部类。但是lambad表达式,比这两种方式都简单。
Lambda表达式对接口的要求
并不是所有的接口都可以使用lambda表达式来简洁实现的。
当实现的接口中的方法过多或过少的时候,lambda表达式都是不适用的。
lambda表达式,只能实现函数式接口。
函数式接口
基础概念
一个接口中,要求实现类必须实现的抽象方法,有且只有一个!这样的接口,就是函数式接口。
// 这个接口中,有且只有一个方法,是实现类必须实现的,因此是一个函数式接口。
interface Test1 {
void test(); // I have one.
}
// 这个接口中,实现类必须要实现的方法,有两个!因此不是一个函数式接口。
interface Test2 {
void test1(); //I have two methods to implement.
void test2();
}
// 无需要实现的方法!因此不是函数式接口。
interface Test3 {
// I don't have an method to implement.
}
// 没有定义任何方法,但继承了Test1,可以从父接口继承到一个抽象的方法。是一个函数式接口。
interface Test4 extends Test1 {
// inherit 继承;define 定义;
// I did not define any methods, but I inherited Test1
}
// 这个接口定义了两个方法,但是default方法子类不是必须实现的。
// 因此,实现类实现这个接口的时候,必须实现的方法只有一个!是一个函数式接口。
interface Test5 {
// although 虽然
void test5(); // Although I have defined two methods, only one method needs to be implemented.
default void test() {}
}
// 这个接口中的 toString 方法,是Object类中定义的方法。
// 此时,实现类在实现接口的时候,toString可以不重写!因为可以从父类Object中继承到!
// 此时,实现类在实现接口的时候,有且只有一个方法是必须要重写的。是一个函数式接口。
interface Test6 {
void test6(); // Although I have defined two methods, there is one method that can not be implemented.
String toString();
}
// 不是函数式接口,因为 toString 可以重写,可以不重写
interface Test7 {
String toString();
}
// 函数式接口
interface Test8 {
void test();
default void test1() {}
static void test2() {}
String toString();
}
@FunctionalInterface
是一个注解,用接口之前,判断这个接口是否是一个函数式接口。如果是函数式接口,没有任何问题。如果不是函数式接口,则会报错。功能类似与@Override
@FunctionalInterface
interface Test1 {
void test();
}
系统内置的若干函数式接口
接口名字 | 参数 | 返回值 | 特殊接口 |
---|---|---|---|
Predicate | T | boolean | IntPredicate: 参数 int,返回值 boolean LongPredicate: 参数 long 返回值 boolean DoublePredicate: 参数 double返回值 boolean |
Consumer | T | void | IntConsumer: 参数 int,返回值 void LongConsumer: 参数 long 返回值 void DoubleConsumer: 参数 double返回值 void |
Function | T | R | ... |
Supplier | 无 | T | ... |
UnaryOperator | T | T | ... |
BinaryOperator | T, T | T | ... |
BiPredicate<L,R> | L,R | boolean | |
BiConsumer<T,U> | T,U | void | |
BiFuction<T,U,R> | T,U | R |
基础语法
lambda表达式,其实本质来讲,就是一个匿名函数。因此在写lambda表达式的时候,不需要关心方法名是什么,也不需要关心返回值类型。只需要关注:参数列表 和 方法体
基础语法:
(参数) -> {
方法体
};
参数部分:方法的参数列表,要求和实现接口中的方法参数部分一直,包括参数的数量和类型。
方法体部分:方法的实现部分,如果接口中定义的方法有返回值,则在实现的时候,注意返回值的返回。
->:分隔参数部分和方法体部分。
// 实现有多参数,有返回值的函数式接口
SingleReturnMultipleParameter lambda6 = (int a, int b) -> {
return a + b;
};
参数的精简
- 参数的类型
- 由于在接口的方法中,已经定义了每个参数的类型是什么。而且在使用lambda表达式实现接口的时候,必须要保证参数的数量和类型需要和接口中的方法保持一致。因此,此时lambda表达式中的参数的类型可以省略不写。
- 注意事项
- 如果需要省略参数的类型,要保证:要省略,每一个参数的类型都必须省略不写。绝对不能出现,有的参数类型省略,有的参数类型没有省略。
// 实现有多参数,有返回值的函数式接口
SingleReturnMultipleParameter lambda6 = (a, b) -> {
return a + b;
};
- 参数的小括号
- 如果方法的参数列表中的参数数量 有且只有一个,此时,参数列表的小括号是可以省略不写的。
- 注意事项:
- 只有当参数的数量是一个的时候
- 省略掉小括号同时必须省略参数的类型
// 实现有一个参数,有返回值的函数式接口
SingleReturnSingleParameter lambda5 = a -> {
return a;
};
方法体的精简
// 省略 return
SingleReturnSingleParameter lambda5 = a -> a;
// 省略大括号
NoneReturnNoneParameter lambda1 = () -> System.out.println("This is a method with no parameters and no return value");