lambda 表达式
Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)
基本语法: (parameters) -> expression
或 (parameters) ->{ statements; }
,由 参数域,"->",实现方法 三部分组成。
注意事项:
- 当参数为空时,参数域由 ()表示即可,多个参数时,参数之间用逗号","分隔;
- 参数不要求指定变量类型,编译器会根据代码上下文推断自动鉴别;
- 当实现方法只有一条语句时,{}可省略,当方法无返回值时,return 关键字可省略;
使用条件:
lambda 表达式主要用来实现行内执行的函数式接口;
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,并且接口需要用_@FunctionalInterface_ 注解修饰,例如:
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
}
在Java8之前,一般用匿名内部类的方式来实现接口内的抽象方法,Java8可以使用lambda表达式来实现,以精简代码;
核心函数式接口
由于lambda表达式是来实现函数式接口的,所以使用之前需要先定义对应的函数式接口,大量使用会导致代码文件琐碎繁复,因此Java8针对常见的使用的场景,已经内置了大部分函数式接口,只有少部分需要我们自己单独定义;
Java内置了四大核心函数式接口
函数式接口 | 类型参数 | 返回类型 | 用途 |
---|---|---|---|
Consumer |
T | void | 对类型为T的对象应用操作,包含方法:void accept(T t); |
Supplier |
无 | T | 返回类型为T的对象,包含方法:T get(); |
Funtional<T,R>函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果是R类型的对象,包含方法:R apply(T,t); |
Predicate |
T | boolean | 确定类型为T的对象是否满足某种约束,并返回boolean值,包含方法:boolean test(T,t); |
其他接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction<T, U, R> | T, U | R | 对类型为 T, U 参数应用操作,返回 R 类型的结果。包含方法为R apply(T t, U u); |
UnaryOperator |
T | T | 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为T apply(T t); |
BinaryOperator |
T, T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为: T apply(T t1, T t2); |
BiConsumer<T, U> | T, U | void | 对 类 型 为 T, U 参数 应 用操作。包含方法为void accept(T t, U u) |
ToIntFunction |
T | intlongdouble | 分 别 计 算 int 、 long 、double、值的函数 |
IntFunction |
intlongdouble | R | 参 数 分 别 为 int 、 long 、double 类型的函数 |
结合lambda表达式和内置函数式接口的代码示例
public void checkSalary(List<Employee> employees, Predicate<Employee> p){
for(Employee employee:employees){
if (p.test(employee)) {
System.out.println(employee.getName());
}
}
}
@Test
public void testLambda(){
List<Employee> employeeList = Arrays.asList(
new Employee("张三",2500,34),
new Employee("李四",4500,45),
new Employee("lisi",3500,35),
new Employee("zhangsan",3000,30));
// 筛选出所有薪水在3000元以上的员工姓名
checkSalary(employeeList,(e)->e.getSalary()>3000);
}
方法引用与构造器引用
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况 :
- 对象::实例方法
- 类::静态方法
- 类::实例方法
//例如
(x) -> System.out.println(x);
//等同于
System.out::println
//例如
BinaryOperator<Double> bo = (x,y) -> Math.pow(x,y);
//等同于
BinaryOperator<Double> bo = Math::pow;
//例如
compare((x,y) -> x.equals(y), "abcdef","abcdef");
//等同于
compare(String::equals,"abc","abc");
注意:当需要引用方法的第一个参数是调用对象,并且第二个参数是需要引用方法的第二个参数(或无参数)时:ClassName::methodName
构造器引用
格式:ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致
数组引用
格式: type[] :: new
// 例如:
Function<Integer,Integer[]> fun = (n) -> new Integer[n];
// 等同于:
Function<Integer,Integer[]> fun = Integer[]::new;