是什么??
有且只有一个抽象方法的接口
场景:
适用于函数式编程场景(使用lambda表达式编程)的接口,函数式接口可以适用于lambda使用的接口。
只有确保接口中有且只有一个抽象方法,java中的lambda才能顺利推到
格式
@FunctionalInterfacepublic interfaceMyInterface {//定义一个抽象方法
public abstract voidmethod();//void method2();
}
函数式接口的使用:
Lambda作为参数
例如:
public classDemo {public static voidshow(MyInterface myInterface){
myInterface.method();
}public static voidmain(String[] args) {//调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
show(newMyInterfaceImp());//调用show方法,方法的参数是一个接口,所以可以传递接口的匿名内部类
show(newMyInterface() {
@Overridepublic voidmethod() {
System.out.println("使用匿名内部类重写接口的抽象方法");
}
});//调用show方法,方法的参数是一个函数式接口,所以,我们可以使用lambda表达式
show(()->{
System.out.println("使用lambda表达式重写接口中的抽象方法");
});//简化lambda表达式
show(()-> System.out.println("简化lambda表达式"));
}
注意:使用匿名内部类回生成.class文件,但是lambda表达式不会,减少JVM的加载
结果:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SNyAjZmJmMkRWO2QWO0ITYihDM4IWZmJmMlRjM0EDN48CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
函数式编程
Lambda的延迟执行减少性能浪费:
例子:
public classDemo01Logger {public static void showLog(intlevel,String msg){if (level == 1){
System.out.println(msg);
}
}public static voidmain(String[] args) {
String msg1= "AAA";
String msg2= "BBB";
String msg3= "CCC";
showLog(1,msg1+msg2+msg3);
}
}
利用lambda表达式优化:
1先定义一个函数式接口
@FunctionalInterfacepublic interfaceMessageBuilder {//定义拼接消息的抽象方法,返回拼接完成的消息
public abstractString builderMsg();
}
public classDemo02Logger {//显示日志方法,
public static void showLog(intlevel,MessageBuilder messageBuilder){if (level == 1){
System.out.println(messageBuilder.builderMsg());
}
}public static voidmain(String[] args) {
String msg1= "AAA";
String msg2= "BBB";
String msg3= "CCC";//调用showLog方法,参数MessageBuilder式一个函数式接口,可以传递Lambda表达式
showLog(1,()->{//返回一个拼接好的字符串
System.out.println("有没有拼接");return msg1+msg2+msg3;
});
}
}
可以通过改变日志级别,看看输出存不存在"有没有拼接"
Lambda作为参数和返回值
public classDemo03Runable {//定义一个方法startThread 方法参数使用函数式接口Runnable
public static voidstartThread(Runnable runnable){newThread(runnable).start();
}public static voidmain(String[] args) {//匿名内部类实现
startThread(newRunnable() {
@Overridepublic voidrun() {
System.out.println(Thread.currentThread().getName()+"线程启动了");
}
});//因为Runnable接口是一个函数式接口,里面只有一个抽象方法run方法,可以使用lambda表达式
startThread(()->{
System.out.println(Thread.currentThread().getName()+"lambda线程启动了");
});
startThread(()->System.out.println(Thread.currentThread().getName()+"优化lambda线程启动了"));
}
}
Lambda作为返回值
public classDemo02Comparator {//定义一个方法,方法的返回值位函数式接口Comparator
public static ComparatorgetComparator(){//方法返回值式一个接口,返回接口的匿名内部类
return new Comparator() {
@Overridepublic intcompare(String o1, String o2) {//安装字符串降序排序
return o1.length() -o2.length();
}
};
}public static ComparatorgetComparator2() {//方法返回值式一个函数式接口,返回接口的lambda表达式
return (String o1, String o2)->{return o1.length() -o2.length();
};
}//优化表达式
public static ComparatorgetComparator3() {//方法返回值式一个函数式接口,返回接口的lambda表达式
return ( o1, o2)-> o1.length() -o2.length();
}public static voidmain(String[] args) {
String[] arr= {"AAAAAAA","BBBB","CCCCCCC"};
System.out.println(Arrays.toString(arr));//对数组进行拍寻
Arrays.sort(arr,getComparator());
System.out.println(Arrays.toString(arr));
}
}
常用的函数式接口:
Supplier接口:
java.util.function.Supplier 接口包含一个无参方法:T get()
作用:用来获取一个泛型参数指定类型的对象数据。
对应的lambda表达式需要提供一个符合泛型类型的对象数据
public classDemo01Supplier {//方法参数传递Supplier接口,泛型String,get返回一个String
public static String getString(Suppliersupplier){returnsupplier.get();
}public static voidmain(String[] args) {//调用getString方法。使用lambda表达大师
String s = getString(()->{return "生成字符串";
});//优化表达式
String s1 = getString(()->"优化生成字符串");
System.out.println(s);
System.out.println(s1);
}
}
结果:
生成字符串
优化生成字符串
简单练习
答案:
public classDemo02Test {//获取数组元素的最大值,参数位supplier接口,泛型Integer
public static Integer getMax(Suppliersupplier){returnsupplier.get();
}public static voidmain(String[] args) {//定义数组
int[] arrint = {111,222,444,333};int maxinarr =getMax(()->{int max = arrint[0];for (inti : arrint) {if(i>max){
max=i;
}
}returnmax;
});
System.out.println(maxinarr);
}
}
Consumer
public classDemo03Consumer {public static void method(String name, Consumerconsumer){
consumer.accept(name);
}public static voidmain(String[] args) {//因为accept有参数,所以lambda表达式需要加入参数。
method("quanzhiqiang",(String name)->{
System.out.println(name);
String reName= newStringBuffer(name).reverse().toString();
System.out.println(reName);
});
}
}
结果:
quanzhiqiang
gnaiqihznauq
Consumer中的默认方法 andThen
public classDemo4Consumer {public static void method(String str , Consumer co1,Consumerco2){
co1.accept(str);
co2.accept(str);
}public static void method1(String str , Consumer co1,Consumerco2){
co1.andThen(co2).accept(str);//执行co1再执行co2,比上面的要简洁一些
}public static voidmain(String[] args) {
method1("quan",
(t)->{//lambda表达式参数的类型,可以省略
System.out.println(t.toUpperCase());
},
(t)->{
System.out.println(t.toLowerCase());
});
}
}
练习:
public classDemo5Consmer {public static void pringinfo(String[] arr , Consumer c1,Consumerc2){for(String s : arr) {
c1.andThen(c2).accept(s);
}
}public static voidmain(String[] args) {
String[] arr= {"AA,N","BB,M","CC,N"};
pringinfo(arr,
( msg)->{//对字符串进行分割,取出姓名
String name = msg.split(",")[0];
System.out.print("姓名:"+name);
},
(msg)->{//对字符串进行分割,取出性别
String sex = msg.split(",")[1];
System.out.println("性别:"+sex);
});
}
}
Predicate接口
public classPredicateTest {//定义方法,参数传递一个字符串,Predicate接口
public static boolean checkString(String s, Predicatepred){returnpred.test(s);
}public static voidmain(String[] args) {
String s="ABCD";
System.out.println(checkString(s,(ss)->{if (ss.length()>5){return true;
}else{return false;
}
})
);
}
}
接口中的默认方法,and or negate:
public classPredicateT {public static boolean checkString(String s, Predicate p1, Predicatep2){//return p1.test(s) && p2.test(s);
return p1.and(p2).test(s);//等价于上面//return p1.or(p2).test(s);//或//return p1.negate().test(s)//negate非
}public static voidmain(String[] args) {
String s= "anbced";boolean re =checkString(s,
(ss)->{return ss.length()>5;
},
(ss)->{return ss.contains("a");
});
System.out.println(re);
}
}
练习:
public classPredicateTest2 {private static void xuanze(String[] arr, Predicate pre1, Predicatepre2){
List stringList =new ArrayList<>();for(String s : arr) {if(pre1.and(pre2).test(s)){
stringList.add(s);
}
}
System.out.println(stringList);
}public static voidmain(String[] args) {
String[] arr= {"1111,N","222,M","44444","N"};
xuanze(arr,
(s)->{return s.split(",")[0].length()==4;
},
(s)->{return s.split(",")[1].equals("N");
});
}
}
Function接口
public classFunctionDemo {public static void exchange(String s, Functionfunction){
Integer i=function.apply(s);//int i1 = function.apply(s);自动拆箱,将Integer类型自动拆成Int类型
System.out.println(i);
}public static voidmain(String[] args) {
String si= "123";
exchange(si,(ss)->{returnInteger.parseInt(ss);
});//优化//exchange(si,(ss)-> Integer.parseInt(ss)//);
}
}
默认方法andThen
public classFunctionDemo2_andThen {private static void change(String s,Function f1,Functionf2){
String ss=f1.andThen(f2).apply(s);
System.out.println(ss);
}public static voidmain(String[] args) {
String s= "123";
change(s,
(s1)->{//把字符串转整数
return Integer.parseInt(s1)+10;
},
(i)->{return i+"";
});
}
}