Lambda表达式可以由编译器推断并转换包装为常规的代码,因此可以使用更少的代码来实现同样的功能。Java中使用Lambda表达式的前提是:必须有“函数式接口”
1.函数式接口
有且仅有一个抽象方法的接口,叫做函数式接口。
注意:
- 是接口
有且仅有一个抽象方法:不能没有,不能有2个及以上,同时可以有默认方法、静态方法等。
如何万无一失地检测当前接口是不是函数式接口呢? 用一个固定的格式写在public interface之前一行即可:
@FunctionalInterface
public interface 函数式接口名{
//.....
}
如下面代码定义的接口就是函数式接口:只有一个抽象方法。
@FunctionalInterface
public interface Calculator {
//抽象方法
public abstract int sum(int x,int z);
//默认方法
public default int getMax(int x,int z) {
return x>z?x:z;
}
}
2.Lambda表达式标准接口
Lambda表达式要想使用,一定要有函数式接口的推断环境
1.要么通过方法的参数类型来确定是哪个函数式接口;
2.要么通过赋值操作来确定是哪个函数式接口;(等号左侧的对象类型)
Lambda的格式就是为了将抽象方法的头,翻译为以下3点:
1.一些参数:方法参数
2.一个箭头:->
3.一些代码:方法体
例如抽象方法:public abstract int sum(int x,int z);
翻译成为Lambda的标准格式:
(int x, int z)->{return x+z;}
省略格式:在Lambda表达式中,凡是可以推导的,都可以省略
1.Lambda表达式中的参数类型可以省略不写;
2.如果参数有且只有一个,那么小括号可以省略不写;
3.如果语句只有一个,那么大括号和return语句也可以省略;
例:定义一个函数式接口Calculator
@FunctionalInterface
public interface Calculator {
public abstract int sum(int x,int z);
}
}
public class LambdaDemo {
public static void main(String[] args) {
//标准格式
method((int x,int y)->{return x+y;});
//省略格式
method((a,b)->a+b);
//根据赋值语句左侧的类型推断
Calculator pa = (int x,int y)->{return x+y;};
method(pa);
//错误写法:
//(int x,int y)->{return x+y;};//没有上下文推断,没有传参数,没有赋值
}
public static void method(Calculator calculator) {
int s = calculator.sum(100,200);
System.out.println(s);
}
}
运行结果:
3.Lambda表达式的冗余
来看一个例子:
首先定义一个类PrintClass,这个类有一个静态方法print,用于打印给定的字符串:
public class PrintClass {
public static void printStr(String str) {
System.out.println(str);
}
}
然后我定义了一个函数式接口PrintMsg :
@FunctionalInterface
public interface PrintMsg {
public abstract void print(String msg);
}
在main函数里我用Lambda表达式指定了接口的作用:
public class LambdaDemo {
public static void main(String[] args) {
methodPrint((String str)-> {System.out.println(str);});
}
public static void methodPrint(PrintMsg printMsg) {
printMsg.print("Jungle");
}
}
运行结果如图:
是我们想要的结果。但是我们发现,在我们定义的类PrintClass里的静态方法printStr已经实现了这个功能,但是在main里又通过Lambda表达式重新写了一遍,这没有必要,能不能通过Lambda表达式直接调用已有的方法呢?
4.Lambda引用类的静态方法和成员方法
上面的问题的答案是肯定的。这即是通过引用类的方法来实现。分为两种,静态方法和成员方法。
对于静态方法,通过类名::静态方法名;
对于成员方方法,通过类的对象名::成员方法名;
还是上面的例子:
public class LambdaDemo {
public static void main(String[] args) {
methodPrint(PrintClass::printStr);//引用类的静态方法
}
public static void methodPrint(PrintMsg printMsg) {
printMsg.print("Jungle");
}
}