前言
肝开题报告
正文
1、函数式接口
概念
函数式接口:有且只有一个抽象方法的接口,称之为函数式接口。当然接口中可以包含其他的方法(默认,静态,私有)
函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可
以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
“语法糖”
是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实
底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部
类的“语法糖”,但是二者在原理上是不同的
格式
只要确保接口中有且仅有一个抽象方法即可: 修饰符 interface 接口名称 { public abstract 返回值类型 方法名称(可选参数信息); // 其他非抽象方法内容 } 注意:接口当中抽象方法的 public abstract 是可以省略的
@FunctionalInterface注解
一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。 需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。 作用:可以检测接口是否是一个函数式接口 是:编译成功 否:编译失败(接口中没有抽象方法或者抽象方法的个数不止一个)
自定义函数式接口
函数式接口的作用:一般可以作为方法的参数和返回值类型public class Demo09FunctionalInterface { // 使用自定义的函数式接口作为方法参数 private static void doSomething(MyFunctionalInterface inter) { inter.myMethod(); // 调用自定义的函数式接口方法 } public static void main(String[] args) { // 调用使用函数式接口的方法 doSomething(() ‐> System.out.println("Lambda执行啦!")); } }
2、函数式编程
Lambda表达式作为方法参数和方法返回值
注意:Lambda表达式是延时执行的
如果抛开实现原理不说,Java中的Lambda表达式可以被当作是匿名内部类的替代品。
如果方法的参数是一个函数式接口类型,那么就可以使用Lambda表达式进行替代。使用Lambda表达式作为方法参数,其实就是使用函数式接口作为方法参数。
例如 java.lang.Runnable 接口就是一个函数式接口,假设有一个 startThread 方法使用该接口作为参数,那么就可以使用Lambda进行传参。这种情况其实和 Thread 类的构造方法参数为 Runnable 没有本质区别。public class Demo01Runnable { public static void startThread(Runnable r) { new Thread(r).start(); } public static void main(String[] args) { startThread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->线程启动了"); } }); startThread(() -> System.out.println(Thread.currentThread().getName() + "-->线程启动了")); } }
类似地,如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式。当需要通过一个方法来获取一个 java.util.Comparator 接口类型的对象作为排序器时,就可以调该方法获取。
public class Demo02Comparator { //定义一个返回值类型使用函数式接口Comparator的方法 public static Comparator<String> getComparator() { //字符串长度降序排序 return (o1,o2)-> o2.length() - o1.length(); } public static void main(String[] args) { String[] arr = {"aaa", "ccccc", "b", "bddc"}; System.out.println(Arrays.toString(arr)); Arrays.sort(arr, getComparator()); System.out.println(Arrays.toString(arr));//[ccccc, bddc, aaa, b] } }
3、常用函数式接口
Supplier接口
java.util.function.Supplier接口仅包含一个无参的方法:T get()。用来获取一个泛型参数指定类型的对象数据
Supplier接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据public class Demo01Supplier { public static String getString(Supplier<String> su) { return su.get(); } public static void main(String[] args) { //调用getString方法,方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式 String s = getString(() -> "胡歌"); System.out.println(s); } }
Consumer接口
java.util.function.Consumer接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。
Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据
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)->{ String s = new StringBuffer(name).reverse().toString(); System.out.println(s); }); } }
Consumer接口的默认方法andThen
作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,再对数据进行消费
例如:
Consumer con1;
Consumer con2;
String s=“hello”;
con1.accept(s);
con2.accept(s);
改为连接两个Consumer接口,再进行消费
con1.andThen(con2).accept(s);谁写在前面谁先消费public class Demo02AndThen { public static void method(String s, Consumer<String> con1, Consumer<String> con2) { //con1.accept(s); //con2.accept(s); //使用andThen方法,把两个Consumer接口连接到一起,再消费数据 con1.andThen(con2).accept(s); } public static void main(String[] args) { //调用Method方法,传递一个字符串,两个Lambda表达式 method("Hello", (s) -> { //消费方式,把字符串转为大写 System.out.println(s.toUpperCase()); }, (s) -> { //消费方式,把字符串转为小写 System.out.println(s.toLowerCase()); }); } }
Predicate接口
java.util.function.Predicate接口
作用:对某种数据类型的数据进行判断,结果返回一个boolean值
Predicate接口中包含一个抽象方法:
boolean test(T t):用来对指定数据类型数据进行判断的方法
返回值:
符合条件:返回true
不符合条件:返回falsepublic class Demo01Predicate { public static boolean checkString(String s, Predicate<String> pre) { return pre.test(s); } public static void main(String[] args) { String s = "NING"; boolean b = checkString(s, (str) -> str.length() > 5); System.out.println(b);//false } }
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法 and
public class Demo02Predicate_and { public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2) { return pre1.and(pre2).test(s); } public static void main(String[] args) { String s = "5bcdde"; boolean b=checkString(s,(s1)-> s1.length() > 5,(s2)-> s2.contains("a")); System.out.println(b); } }
与 and 的“与”类似,默认方法 or 实现逻辑关系中的“或”
public class Demo03Predicate_or { public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2) { return pre1.or(pre2).test(s); } public static void main(String[] args) { String s = "s7777c"; boolean b = checkString(s, s1 -> s1.length() > 5, s2 -> s2.contains("a")); System.out.println(b); } }
“与”、“或”已经了解了,剩下的“非”(取反)也会简单。默认方法 negate
public class Demo04Predicate_negate { 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 = "sbiBC"; boolean b = checkString(s, s1 -> s.length() > 5); System.out.println(b); } }
Function接口
java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件
Function 接口中最主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果
使用的场景例如:将 String 类型转换为 Integer 类型public class Demo01Function { public static void change(String s, Function<String, Integer> fun) { int in = fun.apply(s); System.out.println(in); } public static void main(String[] args) { String s = "239244489"; //传递字符串类型的整数和Lambda表达式 change(s,(String str)->{ return Integer.parseInt(str); }); //优化Lambda表达式 change(s, str-> Integer.parseInt(str)); } }