Lambda 表达式与函数式接口
函数式接口
如果一个接口,只有一个抽象方法,该接口即为函数式接口。函数式接口,即可使用 Lambda 表达式。
如下面的接口
public interface Translate {void translate();}
目前该接口的抽象方法为无参数无返回值
Lambda 表达式
无参无返回值的 Lambda 表达式写法
Translate translate1 = () -> {System.out.println("lambda表达式");
};
有参数,无返回值的 Lambda 表达式写法
// 有参,无返回值 lambda表达式
Translate translate = (int a,int b) -> {int c = a + b;System.out.println(c);
};
参数类型可以省略,因为编译器可以进行类型推断知道他的类型
// 有参,无返回值 lambda表达式
Translate translate = (a,b) -> {int c = a + b;System.out.println(c);
};
只有一个参数时,参数的小括号可以省略
Translate translate1 = a -> {System.out.println("lambda表达式");
};
只有单行语句时的表达式语法
只有单行语句时表达式的{}大括号可以省略
// 无参,无返回值,单行语句
Translate translate1 = () -> System.out.println("lambda表达式");// 有参,无返回值,单行语句
Translate translate = (a,b) -> System.out.println("a + b = " + (a + b));
其实有无返回值,对于 Lambda 表达式的写法并无太大的区别。无非就是有无 return 语句。但是,有返回值的方法,在只有单行语句时,{}大括号和return都可以省略
// 有参,有返回值,单行语句
Translate translate = (a,b) -> a + b;
Lambda 表达式使用作用域之外的局部变量
int c = 0;
// 有参,无返回值 lambda表达式
Translate translate = (a,b) -> a + b + c;
此时,变量c会是隐式final的,无法修改。
函数式接口
@FunctionalInterface
添加 @FunctionalInterface 注解,用于在编译时检测接口是否为函数式接口,如果不是,将会编译报错。
Java 内置的函数式接口
接口名 | 对应函数 | 说明 |
---|---|---|
Consumer<T> 消费型 | void accept(T t); | 对泛型对象t进行相关操作,没有返回值 |
Supplier<T> 供给(生产)型 | T get(); | 返回泛型对象 |
Function<T, R> 函数型 | R apply(T t); | 对泛型对象t进行相关操作,并返回泛型对象R |
Predicate<T> 断言型 | boolean test(T t); | 对泛型对象t进行相关验证,并返回 boolean 验证结果 |
Consumer<T> 消费型
比如我们的实现为打印某个数
Consumer<Integer> c = (a) -> System.out.println(a);
c.accept(1);
Consumer<T> 中的 andThen 方法
此方法的作用为,可以将多个 Consumer 按顺序执行。表示为当前对象调用之后执行另一个Consumer
Consumer<Integer> c = (a) -> System.out.println("c:" + a);
Consumer<Integer> c1 = (a) -> System.out.println("c1:" + a);
c.andThen(c1).accept(1);
Supplier<T> 供给(生产)型
Supplier<Integer> s = () -> 20;
System.out.println(s.get());
Function<T, R> 函数型
Function<String,Integer> fun = (str) -> str.length();
System.out.println(fun.apply("aaa"));
Function<T, R> 中的 andThen 、compose 方法
- andThen 同Consumer,此方法的作用为,可以将多个 Function 按顺序执行。表示为当前对象调用之后执行另一个Function
- compose 与 andThen 方法相反,表示为当前对象调用之前执行另一个 Function
Predicate<T> 断言型
Predicate<Integer> p = t -> t > 20;
System.out.println(p.test(30));
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。前提是方法引用的方法的参数列表和返回值类型与 Lambda 表达式的一致。
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式, 也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
语法格式
构造方法:类名::new
静态方法:类名::方法名
成员方法:对象名::方法名
示例
Consumer<Integer> c = System.out::println;
// 上面写法等价于
Consumer<Integer> c1 = a -> System.out.println(a);
Map<String,Integer> map = new HashMap<>();
map.put("key1",13);
Function<String,Integer> fn = map::get;
System.out.println(fn.apply("key1"));