函数式接口:在Java中是指:有且仅有一个抽象方法的接口。可以包含其他方法(非抽象方法)。
函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。
“语法糖”:是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实底层的实现原理仍然是迭代器,便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部 类的“语法糖”,但是二者在原理上是不同的。
1.2 格式修饰符 interface 接口名称 { public abstract 返回值类型 方法名称(可选参数信息); // 其他非抽象方法内容 }1.3 @FunctionalInterface注解
检测接口是否是函数式接口
与@Override 注解的作用类似,注解: @FunctionalInterface 。使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。(不注解,满足条件不影响实际应用)
1.3 函数式接口的使用public class DemoFunctionalInterface { // 使用自定义的函数式接口作为方法参数 private static void show(MyFunctionalInterface inter) { inter.myMethod(); // 调用自定义的函数式接口方法 } public static void main(String[] args) { // 调用使用函数式接口的方法 show(() ‐> System.out.println("Lambda执行啦!")); } }二 函数式编程 2.1 Lambda的延迟执行
Lambda表达式是延迟执行的,可以提升性能。
public class Demo01Logger { private static void log(int level, String msg) { if (level == 1) { System.out.println(msg); } } public static void main(String[] args) { String msgA = "Hello"; String msgB = "World"; String msgC = "Java"; log(1, msgA + msgB + msgC); } }
优化代码
Lambda表达式使用前提,必须存在函数式接口
public class Demo03Delay { private static void log(int level, MessageBuilder builder) { if (level == 1) { System.out.println(builder.buildMessage()); } } public static void main(String[] args) { String msgA = "Hello"; String msgB = "World"; String msgC = "Java"; log(2, () ‐> { System.out.println("Lambda执行!"); return msgA + msgB + msgC; }); } }2.2使用Lambda作为参数和返回值
例如java.lang.Runnable 接口就是一个函数式接口,假设有一个startThread 方法使用该接口作为参数,那么就可以使用Lambda进行传参。这种情况其实和Thread 类的构造方法参数为Runnable 没有本质区别。
2.2.1 作为参数public class Demo01Runnable { //定义一个方法startThread方法的参数使用函数式接口 public static void startThread(Runnable run){ //开启多线程 new Thread(run).start(); } public static void main(String[] args) { //调用startTread方法,方法参数是一个接口,那么我们就可以传递这个接口的匿名内部类 startThread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了"); } }); //调用startThread方法,方法的参数是一个函数式接口,所以可以传递Lambda表达式 startThread(()->{ System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了"); }); //优化表达式 startThread(()-> System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了")); } }2.2.2 作为返回值
public class DemoCoomparator { //定义一个方法,方法的返回值类型使用函数式接口Comparator public static Comparator三 常用函数式接口 3.1 Supplier接口getComparator(){ //方法的返回值类型是一个函数式接口,那么我们可以返回这个接口的匿名内部类 //方法的返回值类型是一个函数式接口,所以我们可以返回一个Lambda表达式 //继续优化Lambda表达式 return (o1, o2)-> o2.length()-o1.length(); } public static void main(String[] args) { String[] arr = {"abcd","cdef","hijk","hhhhhhh"}; //输出排序前的数组 System.out.println(Arrays.toString(arr)); //调用Array中的sort方法,对字符串数组进行排序 Arrays.sort(arr,getComparator()); //输出排序后的数组 System.out.println(Arrays.toString(arr)); } }
java.util.function.Supplier
称之为生产型接口,指定接口的泛型是什么类型,那么接口中get的方法就会产生什么类型的数据
由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
public class DemoSupplier { //定义方法 传递 Supplier接口 public static String getString(Suppliersup){ return sup.get(); } public static void main(String[] args) { String s = getString(()->{ return "刘德华"; }); System.out.println(s); //Lambda 优化 String s2 = getString(()->"刘德华"); System.out.println(s2); }
}
求数组元素最大元素
import java.util.function.Supplier; public class Demo02Supplier { //定义方法,泛型是Integer public static int getMax(Supplier3.3 Consumer接口sup){ return sup.get(); } public static void main(String[] args) { //定义一个int类型的数组 int[] arr = {100,0,-50,88,-36,758,62}; //调用getMax方法,方法的参数Supplier是一个函数式接口,可以传递Lambda表达式 int maxValue = getMax(()->{ int max = arr[0]; for (int i:arr) { if(i>max){ max = i; } } return max; }); System.out.println(maxValue); } }
Consumer接口 是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据至于怎么消费(使用),需要自定义(输出,计算....)
定义一个方法 方法的参数传递一个字符串的姓名 方法的参数传递Consumer接口,泛型使用String 可以使用Consumer接口消费字符串的姓名
抽象方法:accept Consumer 接口中包含抽象方法void accept(T t) ,意为消费一个指定泛型的数据。
默认方法:andThen 如果一个方法的参数和返回值全都是Consumer 类型(两个Consumer接口),那么就可以实现效果:消费数据的时候,首先做一个 *** 作,然后再做一个 *** 作,实现组合。而这个方法就是Consumer 接口中的default方法andThen
3.4 练习:格式化打印信息//下面的字符串数组当中存有多条信息,请按照格式“ 姓名:XX。性别:XX。”的格式将信息打印出来。要求将打印姓 //名的动作作为第一个Consumer 接口的Lambda实例,将打印性别的动作作为第二个Consumer 接口的Lambda实 //例,将两个Consumer 接口按照顺序“拼接”到一起。 public class Demo01Consumer { public static void printInfo(String[] arr, Consumer con1,Consumer con2){ //遍历字符串数组 for (String message:arr) { //使用andThen方法连接两个Consumer 接口消费字符串 con1.andThen(con2).accept(message); } }
public static void main(String[] args) { //定义字符串类型数组 String[] arr = {"迪丽热巴,女","古力娜扎,女","马尔扎哈,男","刘德华,男"}; //调用printInfo传递一个字符串数组,两个lambda表达式。 printInfo(arr,(message)->{ String name = message.split(",")[0]; System.out.print("姓名:"+name); },(message)->{ String age = message.split(",")[1]; System.out.print("性别:"+ age); }); } }3.5 Predicate接口
对某种类型的数据进行判断,结果返回boolean值。可以使用java.util.function.Predicate 接口。
抽象方法:test
Predicate 接口中包含一个抽象方法: boolean test(T t) 。用于条件判断的场景: 符合条件:返回true
默认方法:and
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法and 。
Predicate接口中有一个方法and,表示并且关系,也可以用于连接两个判断条件 default Predicate and(Predicate super T> other) { Objects.requireNonNull(other); return (t) ‐> test(t) && other.test(t); }
默认方法:or
default Predicateor(Predicate super T> other) { Objects.requireNonNull(other);return (t) ‐> test(t) || other.test(t);}## import java.util.function.Predicate; public class Demo16PredicateAnd { private static void method(Predicate one, Predicate two) { boolean isValid = one.or(two).test("Helloworld"); System.out.println("字符串符合要求吗:" + isValid); } public static void main(String[] args) { method(s ‐> s.contains("H"), s ‐> s.contains("W")); } }
默认方法:negate
剩下的“非”(取反)也会简单。
import java.util.function.Predicate; public class Demo04PredicateNegate { private static void checkString(Predicate3.6 练习:集合信息筛选predicate) { boolean b = predicate.negate().test("abcdefgh"); System.out.println("字符串很长吗:" + b); } public static void main(String[] args) { checkString(s ‐> s.length() < 5); } }
数组当中有多条“姓名+性别”的信息如下,请通过Predicate 接口的拼装将符合要求的字符串筛选到集合 ArrayList 中,需要同时满足两个条件: 1. 必须为女生; 2. 姓名为4个字。
/有两个条件,所以需要用两个Predicate接口,对条件进行判断 //定义一个方法,方法参数传递一个包含人员信息的数组,传递两个Predicate接口 public class Demo05Test {
public static ArrayListfilter(String[] arr, Predicate p1,Predicate p2) { //定义一个ArrayList集合,存储过滤的信息 ArrayList list = new ArrayList<>(); //遍历数组 for (String s:arr) { boolean b = p1.and(p2).test(s) ; //对boolean值进行判断 if (b) { list.add(s) ; } } return list; } public static void main(String[] args) { //定义一个存储字符串的数组 String[] arry = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" }; //调用filter 传递字符串数组和两个Lambda表达式 ArrayList list = filter(arry,(String s)->{ return s.split(",")[1].equals("女"); },(String s)->{ return s.split(",")[0].length()==4; }); //遍历集合 for (String s:list ) { System.out.println(s); } }
}
3.7 Function接口java.util.function.Function
抽象方法:apply
Function 接口中最主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果。使用的场景例如:将String 类型转换为Integer 类型。
默认方法:andThen
Function 接口中有一个默认的andThen 方法,用来进行组合 *** 作。
import java.util.function.Function; public class Demo12FunctionAndThen { private static void method(Function3.8 练习one, Function two) { int num = one.andThen(two).apply("10"); System.out.println(num + 20); } public static void main(String[] args) { method(str‐>Integer.parseInt(str)+10, i ‐> i *= 10); } }
题目 请使用Function 进行函数模型的拼接,按照顺序需要执行的多个函数 *** 作为: String str = "赵丽颖,20"; 1. 将字符串截取数字年龄部分,得到字符串; 2. 将上一步的字符串转换成为int类型的数字; 3. 将上一步的int数字累加100,得到结果int数字。
public class Demo06Test { //定义一个方法,参数传递函姓名和年龄的字符串 public static int change(String s, Functionfun1,Function fun2,Function fun3){ //使用andThen方法把三个转换组合到一起 return fun1.andThen(fun2).andThen(fun3).apply(s); } public static void main(String[] args) { //定义一个字符串 String s1 = "刘德华,50"; int num = change(s1,(String s)->{ return s.split(",")[1]; },(String s)->{ return Integer.parseInt(s); },(Integer i)->{return i+200;}); System.out.println(num); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)