8.函数式接口
函数式接口
概念:一个接口中的抽象方法只有一个,那么这个接口就是一个函数式接口。
1、通过注解检测一个接口是否是一个函数式接口:
@FunctionalInterface
在接口上直接加上注解,如果这个接口是一个函数式接口则不报错,否则编译报错
2、作用:
(1)是Lambda表达式的使用前提
(2)概念层面,为了表示接口就代表这个抽象方法,所以将名起为函数式接口
内置函数式接口
在jdk8之后,官方定义了一些常用的函数式接口,如果以后需要使用类似的接口,直接 使用即可,不需要再单独定义。
分类:
Consumer :消费型接口
void accept(T t)
Supplier :供给型接口
T get()
Function<T,R> :函数型接口
R apply(T t)
Predicate :断言型接口
boolean test(T t);
消费型接口
接口名称:Consumer
抽象方法:void accept(T t):消费一个参数数据
概述:该接口中的方法可以接收一个参数,接收的参数类型由泛型指定,对参数的操作 方式根据该接口的实现类决定,不需要返回值。
拓展的非抽象方法:
default Consumer andThen(Consumer<? super T> after) :
返回一个组合的 Consumer ,按顺序执行该操作,然后执行 after操作。
1 public class consumer { 2 public static void main(String[] args) { 3 System.out.println("1、-----------------------------------"); 4 //想要打印的参数 5 printNum("aaa",s -> System.out.println(s)); 6 7 System.out.println("2、-----------------------------------"); 8 //想要打印该参数字符的个数 9 printNum("aaa",s -> System.out.println(s.length())); 10 11 System.out.println("3、-----------------------------------"); 12 //将参数和其他字符串拼接 13 printNum("aaa",s -> System.out.println("999"+s)); 14 15 System.out.println("4、-----------------------------------"); 16 Consumer<String> s1 = s -> System.out.println(s); 17 Consumer<String> s2 = s -> System.out.println(s.length()); 18 //将s1 和 s2 结合到一起 19 s1.andThen(s2).accept("aaa"); 20 } 21 //方法的功能:打印参数 22 // 打印好处: 23 // 如果方法要使用一个参数,具体参数的使用方式不确定,或者有很多种使用方式 24 // 可以将该参数交给消费型接口去完成该参数的使用 25 // 后续使用该方法时,不仅要传递实际参数,还要传递消费型接口的实现类对象 26 // 消费型接口的对象如何定义: 根据使用的具体需求来定义 27 public static void printNum(String str, Consumer<String > con){ 28 con.accept(str); 29 } 30 } 31 /* 32 1、----------------------------------- 33 aaa 34 2、----------------------------------- 35 3 36 3、----------------------------------- 37 999aaa 38 4、----------------------------------- 39 aaa 40 3
供给型接口
1、接口名:Supplier :
2、抽象方法:T get():该方法不需要参数,它会按照某种逻辑,返回一个具体的数据
3、概述:
该接口也被称为生产型接口,如果指定了泛型是什么类型,那类中的get方法就会返回 一个该类型的一个具体数据。返回的数据,由该接口的实现类对象决定。
1 public static void main(String[] args) { 2 //向集合中添加5个1-100之间的随机数并输出 3 System.out.println(getList(() -> new Random().nextInt(100) + 1)); 4 //向集合中添加5个1-20之间的随机数并输出 5 System.out.println(getList(() -> new Random().nextInt(20) + 1)); 6 } 7 8 //定义一个方法:该方法可以返回一个Integer集合,该集合中的整数范围是:1-100,集合中右五个数据 9 // 如果需要获取一个数据,但是返回的该数据不确定是谁 10 // 可以使用供给型接口来使用该数据 11 // 后续使用该方法时,需要根据调教来给出供给型接口的实现类对象(可以Lambda来实现) 12 // 使用条件是谁,就怎么定义接口的实现类对象 13 public static ArrayList<Integer> getList(Supplier<Integer> sup) { 14 Random r = new Random(); 15 ArrayList<Integer> list = new ArrayList<>(); 16 for (int i = 0; i < 5; i++) { 17 list.add(sup.get()); 18 } 19 return list; 20 } 21 /* 22 [86, 70, 81, 88, 57] 23 [7, 16, 5, 9, 11]
函数型接口
1、接口名:Function<T,R>
2、抽象方法:R apply(T):接收一个数据,操作数据之后,返回一个新的数据
3、概述:
该接口可以接收一个数据,数据的类型根据泛型指定,然后通过该接口的实现类对象对 该数据进行操作,操作之后返回一个新的数据。
4、拓展的非抽象方法:default Function andThen(Function f):
先通过调用者对象处理参数,将处理的结果再通过f对象处理,将两个处理的结果进行返回。
1 public static void main(String[] args) { 2 // 使用该方法时 第一点先传递该方法的参数1 【需要处理的数据】 3 // 第二点要传递该数据的处理条件 【如何处理】 4 System.out.println(function.strInt("aaa", s -> s.length())); 5 System.out.println(function.strInt("123", s -> Integer.parseInt(s))); 6 System.out.println("----------------------------------------------------"); 7 8 Function<String, String> fun1 = s -> "hello" + s; 9 Function<String, Integer> fun2 = s -> s.length(); 10 //将 fun1 和 fun2 两种方式结合到一起 11 Function<String, Integer> fun3 = fun1.andThen(fun2); 12 //接收参数,之后,先使用fun1的方式处理,然后在使用fun2的方式处理,最终处理结果是返回值 13 //将 abc 参数先通过 fun1 方式处理,返回值 helloabc。然后交给 fun2 方式处理 返回个数:8 14 System.out.println(fun3.apply("abc")); 15 } 16 17 //定义一个方法 ,该方法可以接收一个字符串,返回该字符串的个数 18 // 将该字符串转为对应的整数返回 19 public static int strInt(String s, Function<String, Integer> fun) { 20 return fun.apply(s); 21 } 22 /* 23 3 24 123 25 ---------------------------------------------------- 26 8
断言型接口
1、Predicate:
boolean test(T t):对数据做出指定的判断
2、概述:
该接口是一个判断接口,接口可以接收一个指定泛型的参数,并根据该接口的实现类 对象对该参数做出对应的判断,返回只为boolean类型
3、额外功能:
and(Predicate p):先将参数通过调用者判断真假,再将参数通过p判断真假,全真 为真,否则为假
or(Predicate p):全假为假,否则为真
negate():取反
1 public static void main(String[] args) { 2 ArrayList<String> st = new ArrayList<>(); 3 st.add("aac"); 4 st.add("bbc"); 5 st.add("ccc"); 6 7 //在使用该方法时,不仅需要给出需要处理的参数,也要给出判断条件 8 //一旦条件给定之后,将来判断的结果就会随着条件的不同而改变 9 System.out.println(is(st, s -> s.startsWith("a"))); 10 System.out.println(is(st, s -> s.length()==2)); 11 System.out.println("--------------------------------------------"); 12 Predicate<Integer> pre1 = s -> s >= 10 && s <= 100; 13 Predicate<Integer> pre2 = s -> s >= 20 && s <= 80; 14 //连接两个判断方式:全真为真,否则为假 ------ & 15 System.out.println(pre1.and(pre2)); 16 //连接两个判断方式:全假为假,否则为真 ------ | 17 System.out.println(pre1.or(pre2)); 18 //对某个结果取反 19 System.out.println(pre1.negate()); 20 } 21 22 //定义一个方法: 接受一个集合,判断该集合中的内容是否以a开头,如果全部都是,则返回真,否则返回假 23 // 判断字符串每个内容,长度是否满足都为2 24 // 如果需要对数据进行判断,但是判断的规则不同,可以将需要判断的数据交给断言型接口去做 25 public static boolean is(ArrayList<String> list, Predicate<String> pre) { 26 for (String s : list) { 27 if (!pre.test(s)) { 28 return false; 29 } 30 } 31 return true; 32 } 33 \* 34 false 35 false 36 -------------------------------------------- 37 true 38 true 39 true
方法引用
1、概念:
对lambda表达式的扩展,在定义lambda表达式的内容时,如果这个内容之前已经定 义过,那么就不需要再定义一遍,直接调用即可。
2、格式:
如果是一个构造方法:类名::new
如果是一个静态方法:类名::方法名
如果是一个非静态方法:对象名::方法名
1 public class Demo04 { 2 public static void main(String[] args) { 3 //引用构造 4 Consumer<String> con = Person::new; 5 con.accept("宝贝"); 6 //引用静态 7 Consumer<String> con1 = Person::show; 8 con1.accept("宝贝"); 9 //引用非静态 10 Consumer<String> con2 = new Person()::show1; 11 con2.accept("宝贝"); 12 } 13 } 14 class Person{ 15 private String name; 16 17 public Person() { 18 } 19 20 //构造方法 21 public Person(String name){ 22 System.out.println(name+"你真好看!"); 23 } 24 //静态方法 25 public static void show(String name){ 26 System.out.println(name+"你真好看!"); 27 } 28 //非静态方法 29 public void show1(String name){ 30 System.out.println(name+"你真好看!"); 31 } 32 } 33 /* 34 宝贝你真好看! 35 宝贝你真好看! 36 宝贝你真好看!
参考博客:https://blog.csdn.net/PIKapikaaaa/article/details/123487517