Lambda表达式
函数式编程思想概述(java8产物):
强调做什么,而不是以什么形式去做。
面向对象的思想:
- 做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情。
函数式编程思想:
- 只要能获取结果,谁去做的,怎么做的都不重要,重视的是结果,而不是过程。
// 写一个函数式接口
public interface Cook {
void makefood();
}
public class Review1 {
public static void main(String[] args){
// 直接写方法体,它整体就是一个Cook的实现类,编译也不会报错
invoke(()->System.out.println("恰饭啦"));
}
// 这把方法接收参数就用到了刚才定义的接口
public static void invoke(Cook cook) {
cook.makefood();
}
}
Lambda具有可推导就可以省略的特性,下面说下省略规则:
- 小括号内参数的类型可以省略;
- 如果小括号内有且仅有一个参数,则小括号可以省略;
- 如果大括号内有且仅有一个语句,则无论是否具有返回值,都可以省略大括号、return关键字以及语句分号。
使用Lambda的前提:
- 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法,无论是JDK内置的Runnable、Compartor接口还是自定义接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
- 使用Lambda必须具有上下文推导,也是就是方法的参数或者局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
总结:具备上下文推导的唯一方法的接口才可以使用Lambda表达式。
tip:有且仅有一个抽象方法的接口,称为“函数式接口”。
下面介绍几个函数式接口
- Supplier(供应商)
我用这个函数式接口来求一个数组中的最大值,让他返回一个最大值给我,ps:这个接口要求返回值不是必须的
public class Review1 {
public static void main(String[] args){
int[] arr = {1,2,3};
int maxValue = invoke(arr, ()->{
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
max = max > arr[i] ? max : arr[i];
}
return max;
});
System.out.println(maxValue);
}
public static int invoke(int[] arr,Supplier<Integer> supplier) {
return supplier.get();
}
}
- Consumer(消费者)
java.util.function.Consumer接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,没有返回值,其数据类型由泛型决定。
public class Review1 {
public static void main(String[] args){
invoke(10, num->System.out.println(num));
}
public static void invoke(int num,Consumer<Integer> consumer) {
consumer.accept(num);
}
}
- Predicate
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时我们可以使用java.util.function.Predicate接口;
public class Review1 {
public static void main(String[] args){
boolean flag = invoke("hello", str->str.length()>=5);
System.out.println(flag);
}
public static boolean invoke(String str,Predicate<String> predicate) {
return predicate.test(str);
}
}
- Function
java.util.function.Function<T,R>接口来根据一个类型的数据得到另外一个类型的数据,前者成为前置条件,后者成为后置条件;
public class Review1 {
public static void main(String[] args){
Date date = new Date();
String dateFormat = invoke(date,d->{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
return df.format(d);
});
System.out.println(dateFormat);
}
public static String invoke(Date date,Function<Date,String> function) {
return function.apply(date);
}
}
我觉得这些方法都没有具体作用,或者不是那么的强大,我在学这个函数接口的时候,就感觉我一直是个执行者、实现者,我原本是高高在上的指挥者、调用方法的人,可是当我调用函数式接口的时候,我就感觉我得在当前这个方法中去写准备调用的那个方法的具体实现,说白了也就是写了匿名内部类。可能这就是面向接口编程吧,符合七大设计原则的“高层模块不应该依赖地层模块,而应该依赖于抽象;抽象不应该依赖细节,细节应该依赖于抽象”的依赖倒置原则吧,实现这些方法的时候一定要分清好角度,你此时是站在接口内的方法的角度还是实现该方法的角度,你此时是调用者还是实现者,了解了解,有时候看到jdk的一些方法的接收参数为函数式接口的时候,有印象就行。