函数式接口总结及代码演示
1.函数式接口
函数式接口简单定义:有且只有一个抽象方法的接口。
接口中可以包含其他方法:包括默认方法,其他方法,私有方法。
-
定义一个函数式接口
可用@FunctionalInterface注解。
其作用是检测接口是否是一个函数式接口,若是则编译成功,若不是则编译失败。 -
代码演示
@FunctionalInterface
public interface MyFunctionalInterface {
//public abstract可以省略,但有时为了代码清晰易懂,最好写上。
public abstract void method();
}
- 接口实现类为(对比作用)
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
@Override
public void method() {
}
}
- demo
/*
函数式接口的使用:一般可以作为方法的参数和返回值类型
*/
public class Demo {
public static void show(MyFunctionalInterface myInter) {
myInter.method();
}
public static void main(String[] args) {
//传递接口的实现类对象
show(new MyFunctionalInterfaceImpl());
//使用接口的匿名内部类
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("使用匿名内部类重写接口中的抽象方法");
}
});
//调用show方法,方法参数是函数式接口,可以使用Lambda表达式
show(()-> {
System.out.println("使用Lambda表达式重写接口中的抽象方法");
});
}
}
2.Lambda方式的优越性
- 写一个日志案例,首先不使用lambada方式,代码如下
/*
日志案例
发现:以下代码存在性能浪费问题
过程中先拼接字符串,再调用showLog方法
若level不等于1,则还是进行了拼接字符串操作,浪费性能
*/
public class Demo1Logger {
//根据日志的级别显示日志信息的方法
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(2,msg1+msg2+msg3);
}
}
代码存在性能浪费问题,即将level=2的话,是不显示字符串信息的,但是字符串也进行了拼接操作。
- 使用lambda方式
/**
* 使用Lambda优化日志案例
* Lambda优点:延迟加载
* Lambda使用前提:必须存在函数式接口
*/
public class Demo02Lambda {
//定义显示日志的方法
public static void showLog(int level, MessageBuilder mb) {
if(level == 1) {
System.out.println(mb.builderMessage());
}
}
public static void main(String[] args) {
//定义三个日志信息
String msg1 = "Hello";
String msg2 = "World";
String msg3 = "Java";
//调用showLog方法,MessageBuilder是一个函数式接口,所以可以使用lambda表达式
showLog(1,()->{
//测试
System.out.println("不满足条件不执行");
//返回拼接好的字符串
return msg1+msg2+msg3;
});
/**
* 使用lambda表达式作为参数传递。仅仅是把参数传递到showLog方法中,
* 只有满足条件:日志的等级是1级, 才会调用接口中的方法,才会进行字符串的拼接
* 如果条件不满足:接口中的方法不会执行
*/
}
}
这里若将level=2,是不会打印输出语句的,证明若前面条件不成立,lambda是不会执行的,所以可以总结出lambda是具有延迟加载的优点。
3.函数式接口作为参数类型
public class Demo01Runnable {
//Runnable接口就是一个函数式接口
public static void startThread(Runnable run) {
//启用多线程
new Thread(run).start();
}
public static void main(String[] args) {
//调用startThread方法,方法的参数是一个接口,那么可以传递这个接口的匿名内部类
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了");
}
});
//使用lambda表达式 方法的参数是函数式接口 所以使用lambda表达式
startThread(()->{
System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了");
});
}
}
4.常用函数式接口
1.supplier接口
/**
* 常用函数式接口
* Supplier<T> 接口被称之为生产型接口,指定接口的泛型是什么类型,接口中的get方法就会生产什么类型的数据
*/
public class Demo01Supplier {
public static String getString(Supplier<String> sup) {
return sup.get();
}
public static void main(String[] args) {
//调用getString方法,参数是一个函数式接口
String s = getString(()->{
//生产一个字符串并返回
return "james";
});
System.out.println(s);
}
}
应用:返回数组中的最大值
public class Demo2 {
public static int getMax(Supplier<Integer> sup) {
return sup.get();
}
public static void main(String[] args) {
int[] arr = {11,2,23,4,555,51};
int x = getMax(()->{
//获取数组的最大值并返回
//定义一个变量,把数组中第一个元素赋值给该变量,记录数组中元素的最大值
int max = arr[0];
for(int i : arr){
if(max<i){
max = i;
}
}
return max;
});
System.out.println(x);
}
}
02.Consumer接口
Consumer是一个消费型接口,泛型执行什么类型,就可以用accept方法消费什么类型的接口
public class Demo01Consumer {
public static void method(String name, Consumer<String> con) {
con.accept(name);
}
public static void main(String[] args) {
/*
调用method方法,传递name,传递接口
*/
method("james",(t)->{
//对传递的字符串进行消费
//消费方式1 打印
System.out.println(t);
//消费方式2 反转
String rename = new StringBuilder(t).reverse().toString();
System.out.println(rename);
});
}
}
andThen方法
Consumer默认方法 andThen
作用:需要两个Consumer接口,可以结合两个接口组合在一起再对数据进行消费
例如:
Consumer con1
Consumer con2
String s = “hello”
con1.accept(s)
con2.accept(s)
等同于 谁写前面,谁先消费
con1.andThen(con2).accept(s)
public class Demo02Consumer {
//定义一个方法,参数是一个字符串和两个Consumer接口
public static void method(String s, Consumer<String> con1,Consumer<String> con2) {
// con1.accept(s);
// con2.accept(s);
//把两个Consumer连接在一起,使用andThen 先执行con1 后con2
con1.andThen(con2).accept(s);
}
public static void main(String[] args) {
method("James",
(t)->{
System.out.println(t.toUpperCase());
},
(t)->{
System.out.println(t.toLowerCase());
});
}
}
应用:格式化打印信息
public class Demo03Consumer {
public static void printInfo(String[] array, Consumer<String> con1,Consumer<String> con2) {
for(String info : array) {
con1.andThen(con2).accept(info);
}
}
public static void main(String[] args) {
String[] array = {"James,23","Kobe,24","Jordan,23"};
printInfo(array,
(s)->{
System.out.print("姓名:"+s.split(",")[0]);
},
(s)->{
System.out.println("。号码"+s.split(",")[1]+".");
}
);
}
}
3.Predicate接口
判断型接口
Predicate 对某种数据类型的数据进行判断 结果返回一个bool值 boolean test(T t)
public class Demo01Predict {
public static boolean checkString(String s, Predicate<String> pre) {
return pre.test(s);
}
public static void main(String[] args) {
String s = "abcde";
boolean b = checkString(s,(t)->{
return t.length()>5;
});
System.out.println(b);
}
}
应用: 定义一个方法,方法的参数,传递一个字符串 ,传递两个Predicate接口
* 一个用于判断字符串长度是否大于5
* 一个用于判断字符串中是否包含0
* 两个条件必须同时满足
public class Demo02Predict {
public static boolean checkString(String s, Predicate<String> pre1,Predicate<String> pre2) {
return pre1.test(s) && pre2.test(s);
}
public static void main(String[] args) {
String s = "512345";
boolean flag = checkString(s,
(t)->{
return t.length()>5;
},
(t)->{
return t.contains("0");
});
System.out.println(flag);
}
}
4.Function接口
根据一个类型的数据转换为另一个类型的数据
public class DemoFunction {
public static void change(String s, Function<String,Integer> fun) {
Integer in = fun.apply(s);
System.out.println(in);
}
public static void main(String[] args) {
String s = "50";
change(s,(t)->{
return Integer.parseInt(t);
});
}
}
需求:
把String类型转换为Integer 转换后结果+10再转换为String
public class Demo2Function {
public static void change(String s, Function<String,Integer> fun1,Function<Integer,String> fun2) {
String str = fun1.andThen(fun2).apply(s);
System.out.println(str);
}
public static void main(String[] args) {
String s= "1245";
change(s,
(t)->{
return Integer.parseInt(t)+10;
},
(t)->{
return t.toString();
});
}
}
需求:
- 用Function进行函数模型的拼接:
- String str = “james,23”;
- 1.将字符串截取数字年龄部分,得到字符串;
- 2.将上一步的字符串转换为int类型的数据;
- 3.将上一步的数据累加100,得到int数字
public class Demo3Function {
public static void change(String str, Function<String,String> fun1,Function<String,Integer> fun2,Function<Integer,Integer> fun3) {
int age = fun1.andThen(fun2).andThen(fun3).apply(str);
System.out.println(age);
}
public static void main(String[] args) {
String str = "james,23";
change(str,
(String t)->{
return t.split(",")[1];
},
(String t)->{
return Integer.parseInt(t);
},
(Integer t)->{
return t+100;
});
}
}