一、Lambda 表达式的基础语法:
Java8中引入了新的操作符‘’->‘’ 该操作符称为剪头操作符或Lambda操作符,他将Lambda表达式拆分成两个部分:
左侧:Lambda表达式的参数列表 | 右侧:Lambda表达式所知行的功能,即Lambda体 |
---|
语法格式一:无参数,无返回值
Runnable r1 = () ->System.out.println("Hello Lambda!")
语法格式二:有一个参数,无返回值
(param) -> System.out.println(param);
语法格式三:若只有一个参数,左侧的小括号可以省略
param -> System.out.println(param);
语法格式四:有两个以上的参数,有返回值,并且Lambda体中有多条语句则Lambda体必须加大括号“{}”
Comparator <Integer> comparator = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
语法格式五:若Lambda体中只有一条语句,则return和大括号“{}”都可以省略不写
Comparator <Integer> com = (x,y) -> Integer.compare(x,y);
语法格式六:Lambda表达式的参数列表的参数类型可以不写,因为JVM编译器可以通过上下文推断出数据类型,这个过程称之为:类型推断
Comparator <Integer> com = (Integer x,Integer y) -> Integer.compare(x,y);
和
Comparator <Integer> com = (x,y) -> Integer.compare(x,y);
一样;
总结:
上联:左右遇一括号省
下联:左侧推断类型省
横批:能省则省
二、Lambda 表达式需要函数式接口的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用@FunctionalInterface修饰,可以检查是不是函数是接口。
经典案例
/**
* 在员工集合中先按年龄排序,年龄相同的按工资排序
*/
List<Employee> employeeList = Arrays.asList(
new Employee("张无忌",24,5500.00),
new Employee("李茂贞",33,6500.00),
new Employee("杨过",28,5900.00),
new Employee("武庚",28,8400.00),
new Employee("叶星云",35,9000.00),
new Employee("叶辰",20,7400.00),
new Employee("姬如雪",25,5600.00)
);
@Test
public void test7(){
Collections.sort(employeeList,(e1,e2) ->{
if(e1.getAge().compareTo(e2.getAge())== 0){
return e1.getSalary().compareTo(e2.getSalary());
}else {
return Integer.compare(e1.getAge(),e2.getAge());
}
});
for (Employee e:employeeList) {
System.out.println(e);
}
}
输出结果显示:
Employee(name=叶星云, age=35, salary=9000.0)
Employee(name=李茂贞, age=33, salary=6500.0)
Employee(name=杨过, age=28, salary=5900.0)
Employee(name=武庚, age=28, salary=8400.0)
Employee(name=姬如雪, age=25, salary=5600.0)
Employee(name=张无忌, age=24, salary=5500.0)
Employee(name=叶辰, age=20, salary=7400.0)
三、Java8 中内置的四个核心函数式接口
1、Comsumer :消费型接口
void accept(T t);
2、Supplier: 供给型接口
T get();
3、Function<T,R>: 函数型接口
R apply(T t);
4、Predicate :断言型接口
boolean test(T t);
重要小结:在使用Lambda函数式接口之前需要先去构建业务接口,然后在具体的代码中调用构建的接口并且在构建的接口调用时具体实现函数式接口;
四、方法引用:若Lambda体中的内容已经有方法实现了,则使用“方法引用”
(理解为:“方法引用”是Lambda表达式的另外一种表现形式)。
主要有三中语法格式:
注意:Lambda 体中的参数列表返回值类型要与函数式接口中抽象方法的返回值类型保持一致;
1、对象::实例方法名
Consumer<String> con = x -> System.out.println(x);
已有方法实现:
Consumer<String> con = System.out::println;
再有:
Employee emp = new Employee("张无忌","18","2000");
Supplier<Integer> supp = emp::getAge;
2、类::静态方法名
Comparator<Integer> com = (x,y) -> Integer.compara(x,y);
已有方法实现则可以写为:
Comparator<Integer> com = Integer::comapra;
3、类::实例方法名
注意:若Lambda 参数列表中第一个参数是实例方法的调用者,并且第二参数是实例方法的参数时,可以使用ClassName::metohd。
由于
BiPredicate<String ,String> bip = (x,y) ->x.equals(y);
满足上述条件则可写成:
BiPredicate<String ,String> bipe = String::equals;
五、构造器引用
格式:ClassName::new
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
Supplier<Employee> supplier = () ->new Employee();
可以写成:
Supplier<Employee> employeeSupplier = Employee::new;
六、数组引用
格式:Type[] ::new
Function<Integer, String[]> fun = x -> new String[x];
String[] array = fun.apply(20);
System.out.println(array.length);
则输出的数组长度为:20
可以写成:
Function<Integer, String[]> fun = String[]::new;
String[] array = fun.apply(20);
System.out.println(array.length);