Lambda 表达式是Java8以后的新特性,Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑,相应的带来了新的学习成本。
Lambda语法特征主要有以下四点:
1. 可选的类型声明:
不需要声明参数类型,编译器可以统一识别参数值。如:
() -> 15
2. 可选的参数圆括号:
一个参数无需定义圆括号,但多个参数需要定义圆括号。如:
x -> 2 * x
3. 可选的大括号:
如果主体包含了一个语句,就不需要使用大括号。如:
(x, y) -> x – y
4. 可选的返回关键字:
如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
(int x, int y) -> { return x * y; };
Lambda表达式实现的原理:
要实现Lambda表达式,必须先有函数式接口,那怎样才能定义一个函数式接口呢,接口需具有唯一的一个抽像方法,可以定义默认方法、静态方法、定义java.lang.Object里的public方法,再IDE中可以使用@FunctionalInterface注解修饰不报错即可。至于为什么只能有一个没有实现的方法,看完下面的实现原理就能很好的明白。
@FunctionalInterface
interface Print<T> {
public void print(T x);
default void doSomeMoreWork1(){
// Method body
}
static void printHello(){
System.out.println("Hello");
}
@Override
boolean equals(Object obj);
}
在编译器由Java编译成class是,会把包含Lambda表达式的方法按照Java自己的规则生成一个方法,而这个方法的参数就是Lambda -> 前的参数,方法内的处理逻辑即使 -> 后的内容,所以如果函数式接口有一个以上的抽象方法就会导致编译器不知道该让谁去实现Lambda表达式。
我们源码写的是这样的。
public class LambdaTest {
public static void printString(String s, Print<String> print) {
print.print(s);
}
public static void main(String[] args) {
printString("test", (x) -> System.out.println(x));
}
}
@FunctionalInterface
interface Print<T> {
public void print(T x);
}
经过编译后通过Class文件反编译回Java是这样的
public class LambdaTest {
public static void PrintString(String s, Print<String> print) {
print.print(s);
}
public static void main(String[] args) {
PrintString("test", new LambdaTest$$Lambda$1());
}
private static void lambda$main$0(String x) {
System.out.println(x);
}
static final class LambdaTest$$Lambda$1 implements Print {
public void print(Object obj) {
LambdaTest.lambda$main$0((String) obj);
}
private LambdaTest$$Lambda$1() {
}
}
}
@FunctionalInterface
interface Print<T> {
public void print(T x);
}
这里是摘自https://blog.csdn.net/jiankunking/article/details/79825928,看原文更容易理解。
四大内置核心函数式接口
1. Consumer:消费型接口 void accept(T t);
消费型接口就是传进去参数经过表达式处理,没有返回值。
public void test(){
shopping(1000,(x)-> System.out.println("今天购物发了"+x+"元"));
}
public void shopping(double money, Consumer<Double> con){
con.accept(money);
}
2. Supplier :供给型接口 T get();
供给型接口就是无中生有,不传参经过表达式处理返回值,比如生成随机数
public void test2(){
List<Integer> numList=getNumList(3,()->(int)(Math.random()*10));
}
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list=new ArrayList<>();
for (int i=0;i<num;i++){
Integer n=sup.get();
list.add(n);
}
return list;
}
3. Function<T,R>: 函数型接口 R apply(T t);
函数型接口有传参有返回值。
public void test3(){
String newStr= handlerStr("helloworld",(str)->str.substring(3,6));
System.out.println(newStr);
}
public String handlerStr(String str, Function<String,String> fun){
return fun.apply(str);
}
4. Predicate: 断言型接口 boolean test(T t)
返回true或者false
public void test4(){
List<String> list= Arrays.asList("idea","eclipse","predicate","function");
List<String> returnList= filterStr(list,(str)->str.length()>4);
}
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> newList=new ArrayList<>();
for (String str:list) {
if(pre.test(str)){
newList.add(str);
}
}
return newList;
}