目录
一、概述
1、概念
有且只有一个抽象方法的接口(可以有其他默认方法、静态方法);
函数式接口就是可以写成Lambda表达式的接口;
备注:
“语法糖”是指使用更加方便,但是原理不变的代码语法;例如遍历集合时使用的for-each语法,其实底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda表达式可以被当做是匿名内部类的“语法糖”,但是二者与原理上是不同的;
2、格式
只要确保有且仅有一个抽象方法即可
修饰符 interface 接口名称{
public static 返回值类型 方法名称(可选参数信息)
//其他非抽象方法内容
}
3、@FunctionalInterface注解
此注解限定该接口必须是有且仅有一个抽象方法的函数式接口,否则编译报错;
二、函数式接口的使用
1、通过将接口作为方法的参数使用
函数式接口:
package the_function_interface;
@FunctionalInterface//此注解限定该接口必须是一个函数式接口,否则编译报错
public interface MyInterface {
//唯一抽象方法
void method();
}
测试类:
package the_function_interface;
public class Test {
public static void main(String[] args) {
//通过将接口作为方法的参数使用
//1、调用show方法,参数是一个接口,可以传一个接口实现类进去
show(new MyInterfaceImpl());
//2、调用show方法,参数是一个接口,可以传递接口的匿名内部类
show(new MyInterface() {
@Override
public void method() {
System.out.println("通过匿名内部类使用");
}
});
//3、调用show方法,参数是一个接口,而且接口是一个函数式接口,可以使用Lambda
show(() -> {
System.out.println("通过Lambda使用");
});
//4、简化后的Lambda
show(()-> System.out.println("最简化的Lambda"));
}
private static void show(MyInterface myInterface){
myInterface.method();
}
}
2、通过将接口作为方法的返回值使用
函数式接口:
package the_function_interface;
@FunctionalInterface
public interface MyInterface01 {
int getAge();
}
测试类:
package the_function_interface;
public class Test01 {
public static void main(String[] args) {
int age = 10;
System.out.println(showAge(age).getAge());//10
}
private static MyInterface01 showAge(int age){
return ()-> age;
}
}
三、函数式编程
1、Lambda的延迟执行
有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费。而Lambda表达式是延迟执行的,这正好可以作为解决方案,提升性能。
2、性能浪费的日志案例
package the_function_interface;
public class LogTest {
public static void main(String[] args) {
String msg1 = "你好!";
String msg2 = "Hello!";
String msg3 = "其他";
//传递日志级别为1需要打印,拼接三个字符串不浪费性能
showLog(1,msg1+msg2+msg3);
//传递日志级别为1不需要打印,拼接三个字符浪费性能
showLog(2,msg1+msg2+msg3);
// 总结:有部分代码执行了,反不一定会用到它的执行结果
}
private static void showLog(int level,String message){
if(level==1){
System.out.println(message);
}
}
}
3、使用Lambda表达式优化日志案例
Lambda的特点:延迟执行;
Lambda的使用前提:必须存在函数式接口;
代码:
package the_function_interface;
public class LogLambdaTest {
public static void main(String[] args) {
String msg1 = "你好!";
String msg2 = "hello!";
String msg3 = "其他!";
//当Lambda表达式作为参数传递,满足等级条件的话才会执行msg1+msg2+msg3
showLog(1,()->msg1+msg2+msg3);
//当Lambda表达式作为参数传递,不满足等级条件的话不会执行msg1+msg2+msg3
showLog(2,()->msg1+msg2+msg3);
//Lambda延迟执行的特点,就这样带来了避免资源浪费和提升性能
}
private static void showLog(int level,Message message){
if(level==1){
System.out.println(message.buildMessage());
}
}
}
四、常用的函数式接口
1、Supplier<T>接口
介绍:
Supplier<T>接口包含一个无参方法get(),用来获取一个泛型参数指定类型的对象数据;
Supplier<T>接口被称之为生产型接口,指定接口的泛型是什么类似,那么接口中的get方法就生产什么样的数据类型;
使用:
package the_function_interface;
import java.util.function.Supplier;
public class SupplierTest {
public static void main(String[] args) {
System.out.println(getString(()->"这就是你要的字符串!"));
//这就是你要的字符串!
}
private static String getString(Supplier<String> sup){
return sup.get();
}
}
2、Consumer<T>接口
介绍:
Consumer<T>接口包含一个带参方法accepy(<T>),用来消费一个泛型参数指定类型的对象数据;
Consumer<T>接口被称之为消费型接口,指定接口的泛型是什么类似,那么接口中的accept方法就消费什么样的数据类型;
使用:
package the_function_interface;
import java.util.function.Consumer;
public class ConsumerTest {
public static void main(String[] args) {
use("这就是要消费的数据", System.out::println);
//这就是要消费的数据
}
private static void use(String s, Consumer<String> consumer){
consumer.accept(s);
}
}
3、Consumer<T>接口的默认方法andThen
作用:
把两个Consumer接口组合到一起,对数据进行消费;
使用:
package the_function_interface;
import java.util.function.Consumer;
public class ConsumerTest {
public static void main(String[] args) {
use("这就是要消费的数据", System.out::println,s -> System.out.println(s.toCharArray()[0]));
//这就是要消费的数据
}
private static void use(String s, Consumer<String> consumer1,Consumer<String> consumer2){
consumer1.accept(s);//这就是要消费的数据
consumer2.accept(s);//这
//上面两行可以写成这样
consumer1.andThen(consumer2).accept(s);
//这就是要消费的数据
//这
}
}
4、Predicate<T>接口
作用:
判断所制定的数据类型的数据进行判断(test(<T>)方法);
使用:
package the_function_interface;
import java.util.function.Predicate;
public class PredicateTest {
public static void main(String[] args) {
System.out.println(judge(1,(i)-> i>0));//true
}
private static boolean judge(int i, Predicate<Integer> predicate){
return predicate.test(i);
}
}
5、Predicate<T>接口的默认方法and
作用:
就是“且”的效果,相当于&&;
使用:
package the_function_interface;
import java.util.function.Predicate;
public class PredicateTest {
public static void main(String[] args) {
System.out.println(judge(5,(i)-> i>3,(i)-> i>6));//false
}
private static boolean judge(int i, Predicate<Integer> predicate1,Predicate<Integer> predicate2){
// return predicate1.test(i) && predicate2.test(i);
//上面可以这样写
return predicate1.and(predicate2).test(i);
}
}
6、Predicate<T>接口的默认方法or
作用:
就是“或”的效果,相当于||;
使用:
package the_function_interface;
import java.util.function.Predicate;
public class PredicateTest {
public static void main(String[] args) {
System.out.println(judge(5,(i)-> i>3,(i)-> i>6));//true
}
private static boolean judge(int i, Predicate<Integer> predicate1,Predicate<Integer> predicate2){
// return predicate1.test(i) || predicate2.test(i);
//上面可以这样写
return predicate1.or(predicate2).test(i);
}
}
7、Function<T,R>接口
作用:
将数据类型1(T)转换成数据类型2(R);
使用:
package the_function_interface;
import java.util.function.Function;
public class FunctionTest {
public static void main(String[] args) {
change("100",Integer::parseInt);
}
private static void change(String s, Function<String,Integer> function){
System.out.println(function.apply(s));//100
}
}
8、Function<T,R>接口的默认方法andThen
作用:
把两个Function接口组合到一起,对数据进行转换;
使用:
package the_function_interface;
import java.util.function.Function;
public class FunctionTest {
public static void main(String[] args) {
change("100",Integer::parseInt,String::valueOf);
}
private static void change(String s, Function<String,Integer> function1,Function<Integer,String> function2){
System.out.println(function1.apply(s));//100
System.out.println(function2.apply(function1.apply(s)));//100
}
}