概念
函数式接口在Java中是指:有且仅有一个抽象方法的接口。
函数式接口,即适用于函数式变成场景的接口。而Java中函数式变成体现就是Lambda
,所以函数式接口就是适用于Lambda
使用的接口。只有确保接口中有且仅有一个抽象方法,Java
中的Lambda才能被顺利的进行推导。
语法糖
是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的forEach语法,其实底层实现原理仍然是迭代器。从应用层面来讲,Java
中的Lambda
也可以被当作是匿名内部类的语法糖
,但是二者在原理上是不相同的。
格式
只要确保接口中有且仅有一个抽象方法即可:
修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数);
// 其他非抽象方法内容
}
Java中接口的特性:
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
- 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
- 接口中的方法都是公有的。
所以我们可以省略public abstract
的修饰,所以定义一个函数式接口就变得很简单:
public interface MyFunctionalInterface {
void hello();
}
@FunctionalInterface
注解
Java8
中专门为函数式接口引入了一个新的注解:@FunctionalInterface
。该注解可用于一个接口的定义上
@FunctionalInterface
public interface MyFunctionalInterface {
abstract void hello();
}
添加这个注解之后,如果接口中存在多个方法或者没有方法,就会报错,它的作用就是检测接口是否是一个函数式接口。(接口方法都是隐式抽象所以为了简化直接称为方法,而不再加抽象修饰)
函数式接口的使用
public class Demo1 {
// 定义一个方法,参数使用函数式接口
public static void show (MyFunctionalInterface myInterface) {
myInterface.hello();
}
public static void main(String[] args) {
// 调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
show(new MyFunctionalInterface() {
// 使用匿名内部类重写方法
@Override
public void hello() {
System.out.println("我是函数式接口中的方法hello...");
}
});
// 调用show方法,方法的参数一个函数时接口,所以可以使用Lambda表达式
show(()->{
System.out.println("使用Lambda表达式重写接口中的抽象方法。。。。");
});
// 简化Lambda表达式
show(()-> System.out.println("这是简化后的Lambda表达式写法。。"));
}
}
函数式编程
Lambda的延迟执行
有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费。而Lambda
表达式是延迟执行的,这正好可以作为解决方案,提升性能。
性能浪费的日志案例
注:日志可以帮助我们快速的定位问题,记录程序运行过程中的情况,以便项目的监控和优化。
一种典型的场景就是对参数进行有条件使用,例如对日志消息进行拼接后,在满足条件的情况下进行打印输出:
public class Demo01Logger {
// 定义一个根据日志级别显示日志信息的方法
public static void showLog(int level, String message) {
// 对日志的等级进行判断,如果级别是1那么输出日志信息
if (level == 1) {
System.out.println(message);
}
}
public static void main(String[] args) {
// 定义三个日志信息
String msg1 = "hello";
String msg2 = "world";
String msg3 = "Java";
//调用showLog方法,传递日志级别和日志信息
showLog(1, msg1 + msg2 + msg3);
showLog(2, msg1 + msg2 + msg3);
showLog(