函数式接口
有且仅有一个抽象方法的接口称为 函数式接口
为了确保函数式接口有且仅有一个抽象方法,要使用注解@FunctionalInterface,如果出现多于一个抽象方法或者没有抽象方法会编译报错
函数式接口一般作为方法的参数和返回值类型使用
-
使用函数式接口的四种方式:
接口:
public interface Action {
void run(String sth);
}实现类:
public class ActionImpl implements Action{
@Override
public void run(String sth) {
System.out.println("say: " + sth);
}
}Demo
public class DemoInterface {
public static void showRun(Action act){
act.run("实现类使用方法");
}
public static void main(String[] args) {
// 1.实现类对象
showRun(new ActionImpl());// 2. 匿名内部类
showRun(new Action() {
@Override
public void run(String sth) {
System.out.println("使用匿名内部类使用方法");
}
});
// 3. Lambda
showRun((String sth)->{
System.out.println("使用Lambda表达式使用方法");
});
// 4. 优化Lambda
showRun(sth->System.out.println("使用优化Lambda表达式使用方法"));
}
}其中Lambda和匿名内部类使用效果上几乎一致,但是底层原理则不同,其中匿名内部类执行后会有xxx$1.class文件,而Lambda表达式则不会有这个文件
Lambda延迟执行
日志文件:当方法参数等级为1,会打印信息,如果不为1,则什么也不做。
等级不为1时,方法也会先加载信息参数,假设该参数为拼接字符串,那么此时就会出现性能浪费,因为拼接字符串后却没有使用。
代码:
public class DemoLog {
public static void showMes(int level , String mes){
if (level == 1){
System.out.println(mes);
}
}
public static void main(String[] args) {
String a = "这里的";
String b = "山路";
String c = "十八弯";
showMes(1,a+b+c);
// 先拼接 后加载方法 判断不为1 不作为 性能浪费
showMes(2,a+b+c);
}
}
解决方法,使用Lambda表达式,其中Lambda表达式有个特点,就是延迟执行
public interface MessageBuilder {
public abstract String mesConcat();
}
public class DemoLogLambda {
public static void showMes(int level , MessageBuilder mb){
if (level == 1){
System.out.println(mb.mesConcat());
}
}
public static void main(String[] args) {
String a = "这里的";
String b = "山路";
String c = "十八弯";
// 如果等级为1 判断后使用接口中方法 拼接字符串
// 如果等级不为1 则什么也不做
// 提高了程序的效率,避免了性能浪费
showMes(1,()-> {return a+b+c;});
}
}
Lambda表达式作为参数
前提是函数式接口作为参数
[图片上传失败...(image-9a3910-1631103526996)]
public class DemoThreadLambda {
public static void startThread(Runnable run){
new Thread(run).start();
}
public static void main(String[] args) {
startThread(()->{
System.out.println("使用Lambda开启线程"+Thread.currentThread().getName());
});
// Lambda表达式为接口中实现的唯一抽象方法内容
startThread(()->System.out.println("使用Lambda开启线程"+Thread.currentThread().getName()));
}
}
使用Lambda作为返回值
前提是函数式接口作为返回值
[图片上传失败...(image-1b247-1631103526996)]
public class DemoCompLambda {
public static Comparator<String> getComparator(){
// 排序规则 降序
// 匿名内部类
/return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
};/
// 由于Comparator为函数式接口 所以可以使用Lambda表达式
// return (String o1, String o2)->{return o2.length() - o1.length()};
// Lambda表达式优化
return (o1,o2)-> o2.length()-o1.length();
}
public static void main(String[] args) {
String[] arr = {"aaaa","b","cc","dddddddddddddd"};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr,getComparator());
System.out.println(Arrays.toString(arr));
}
}
Lambda优化:在简化时 如果{}内只有一行代码 可以省略 { } 和 ; 如果有return 可以省略return
如果 () 参数列表中数据类型一样可以省略数据类型
常用函数式接口
常用的函数式接口在包 java.util.function包中
-
Supplier<T>
java.util.function.Supplier
接口 中有唯一方法 <T>get() 就是接口泛型为什么类型参数,方法返回值就是什么类型数据
使用Supplier接口获取数组中最大值
代码:
public class DemoSupMax {
public static int getMax(Supplier<Integer> sup){
return sup.get();
}
// 使用Supplier获取数组最大值
public static void main(String[] args) {
int[] nums = {10,22,43,1,54,22,3};
// 匿名内部类
/*int max = getMax(new Supplier<Integer>() {
@Override
public Integer get() {
int max = 0;
for(int i:nums){
if (i > max)
max = i;
}
return max;
}
});
*/
int res = getMax(() -> {
int max = 0;
for(int i:nums){
if (i>max)
max = i;
}
return max;
});
System.out.println("max: " +res);
}
} -
Consumer<T>接口
java.util.function.Consumer
该接口中有一个唯一抽象方法,void accept(T t) 表示接口为什么数据类型泛型,accept就可以消费什么类型数据
对于如何使用数据 自定义
public class DemoConsumer {
public static void revString(String name, Consumer<String> con){
con.accept(name);
}
// 反转字符串
public static void main(String[] args) {
String name = "赵丽颖";
// 链式编程
// StringBuilder的反转字符串方法reverse
revString(name,(String str)->System.out.println(new StringBuilder(name).reverse().toString()));
}
}默认方法:andThen
源码:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
> <? super T> 下界通配符 只能使用T 或者T的父类
示例:
public class DemoConDefault {
public static void useString(String str, Consumer<String> con1,Consumer<String> con2){
// con1.accept(str); // 大写
// con2.accept(str); // 小写
// 谁写在前面 谁先执行(消费数据)
con1.andThen(con2).accept(str);
}
public static void main(String[] args) {
String s = "Hello";
useString(s,(str)->{
System.out.println(str.toUpperCase());
},(str)->{
System.out.println(str.toLowerCase());
});
}
}
练习:
[图片上传失败...(image-cec6ff-1631103526995)]
代码:
public class DemoConExam {
public static void ConcatInfo(String[] strings, Consumer<String> con1, Consumer<String> con2){
// con1 姓名 con2 性别
for(String s:strings){
con1.andThen(con2).accept(s);
}
}
public static void main(String[] args) {
String[] arr = {"灶门炭治郎,男","我妻善逸,男","香奈乎,女","蝴蝶忍,女"};
ConcatInfo(arr,(s)->{
String[] strs = s.split(",");
System.out.print("姓名:" +strs[0]+" ");
},(s)->{
String[] strs = s.split(",");
System.out.println("性别:" +strs[1]);
});
}
}
-
Predicate接口
java.util.function.Predicate<T>接口
主要用于判断,其中抽象方法test(T t) 判断T类型数据 boolean test (T t)
public class DemoPredicate {
public static boolean isLen(String string, Predicate<String> pre){
return pre.test(string);
}
// 判断长度是否大于5
public static void main(String[] args) {
String s = "abc";
// 因为是函数式接口所以可以使用Lambda表达式
/boolean b = isLen(s,(String str)->{
return str.length()>5;
});/
// 优化Lambda
// 由于只有一个参数所以可以省略() 和 数据类型
// 并且只有一行代码 所以可以省略{} ; 和 return
boolean b = isLen(s,str->str.length()>5);
System.out.println(b);
}
}默认方法:and
逻辑 与 有假则假
源码:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}示例:
public class DemoPredicateAnd {
public static boolean booAnd(String s, Predicate<String> pre1,Predicate<String> pre2){
// return pre1.test(s) && pre2.test(s);
return pre1.and(pre2).test(s);
}
// 判断字符串 是否包含a 并且 长度大于3 必须都满足
public static void main(String[] args) {
String s = "dsjai";
// 链式编程
System.out.println(booAnd(s, str -> s.contains("a"), str -> str.length() > 3));
}
}默认方法:or
逻辑或 有真则真
源码:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}示例:
public class DemoPredicateAnd {
public static boolean booAnd(String s, Predicate<String> pre1,Predicate<String> pre2){
// return pre1.test(s) && pre2.test(s);
// return pre1.and(pre2).test(s);
return pre1.or(pre2).test(s);
}
// 判断字符串 是否包含a 或者 长度大于3 必须都满足
public static void main(String[] args) {
String s = "dsjai";
// 链式编程
System.out.println(booAnd(s, str -> s.contains("a"), str -> str.length() > 3));
}
}默认方法:negate
逻辑非 取反
源码:
default Predicate<T> negate() {
return (t) -> !test(t);
}示例:
public class DemoPredicateNegate {
// 不大于5 返回true
public static boolean checkString(String s, Predicate<String> pre){
// return !pre.test(s);
return pre.negate().test(s);
}
public static void main(String[] args) {
String s = "acc";
System.out.println(checkString(s, str -> str.length() > 5));
}
}
练习:集合信息筛选
[图片上传失败...(image-4bb567-1631103526987)]
代码:
public class DemoPredicateExam {
public static List<String> chooseInfo(String[] arr, Predicate<String> pre1, Predicate<String> pre2){
List<String> list = new ArrayList<>();
for (String s:arr){
if (pre1.and(pre2).test(s)){
list.add(s);
}
}
return list;
}
public static void main(String[] args) {
String[] arr = {"迪丽热巴,女","古力娜扎,女","我妻善逸,男","赵丽颖,女"};
// 这里切割出来的字符串与比较的字符串不是同一个地址值
// 不能使用 == 要用equals
List<String> infos = chooseInfo(arr, s -> s.split(",")[0].length()>=4
, s -> "女".equals(s.split(",")[1]));
System.out.println(infos);
}
}
-
Function接口
java.util.function.Function<T,R>
抽象方法 R apply(T t) 将T类型数据转换为R数据类型
源码:
R apply(T t);
代码:
public class DemoFunction {
public static void change(String s, Function<String, Integer> fun){
Integer i = fun.apply(s);
System.out.println(i + ": " + i.getClass());
}
// 将字符串类型转换为Integer
public static void main(String[] args) {
String s = "123";
change(s,num->Integer.parseInt(num));
}
}
默认方法andThen 组合转换数据案例:将字符串类型的数字转换为Integer 加 10
再转换为字符串
代码:
public class DemoFuncAndThen {
public static void method(String s, Function<String,Integer> fun1,Function<Integer,String> fun2){
System.out.println(fun1.andThen(fun2).apply(s)+": "+fun1.andThen(fun2).apply(s).getClass());
}public static void main(String[] args) {
String s = "123";
method(s,num->Integer.parseInt(num)+10,num->Integer.toString(num));
}
}Lambda表达式中 () 只有一个参数时 可省略 数据类型和()
{} 中只有一行代码 且有 return 可省略 {} ;和return
[图片上传失败...(image-1a0449-1631103526986)]
代码:
public class DemoFuncExam {
public static void exam(String s, Function<String,String> fun1,Function<String,Integer> fun2,Function<Integer,Integer> fun3){Integer i = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.println(i+": "+i.getClass());
}
public static void main(String[] args) {
String s = "迪丽热巴,19";
exam(s,str->str.split(",")[1],str->Integer.parseInt(str),num->num+100);
}
}