1什么是函数式接口:
2如何判断函数式接口是否成功创建:使用FUNCTIONINTERFACE注解(使用方法同@override)
3 函数式接口的使用:一般可以作为方法的参数和返回值来使用(在这里重新复习接口内容知识)
1.如果主方法调用的方法,该方法传递进来的参数是一个接口,那么可以:
1主方法中传入的参数可以是:接口的实现类
2主方法中传入的参数可以是:接口的匿名内部类
3如果方法中的参数是函数式接口,则可以使用lambda表达式
package com.bed.hanshushijiekou;
//使用三种方法来调用接口的抽象方法
public class mainfangfa {
//第一种方法:直接把接口传递进来,然后调用接口中的方法。
public static void method1(myInterface myinter){
myinter.method();
}
public static void main(String[] args) {
//第二种方法:调用方法一,然后参数传递接口的实现类
method1(new myInterfaceimpl());
//第三种方法。参数传递接口的匿名内部类。
method1(new myInterface() {
@Override
public void method() {
System.out.println("传递接口的匿名内部类重写接口中的方法");
}
});
//同样是第三种方法使用lambda表达式
method1(()-> System.out.println("使用lambda表达式传递接口的匿名内部类重写接口中的方法"));
}
}
补充知识点:lambda表达式可以看作是匿名内部类的语法糖。但是lambda表达式省去
了.class文件,所以效率更高
添加知识点:lambda表达式的延迟性:
现有如下代码 :
日志只有传入等级为一级时才显示信息,当传入等级为其他等级时,msg1+msg2+msg3的组
合操作就是多余的。这时我们可以使用lambda表达式的延时特性来节省资源。避免性能浪费 代码实现:
//创建一个接口里面有一个抽象类方法
package com.bed.hanshushijiekou.demo01;
public interface msgplus {
public abstract String msgplus();
}
//执行日志
package com.bed.hanshushijiekou.demo01;
public class RiZhishow {
public static void msgshow(int level,msgplus msg){
if(level==1){
System.out.println(msg.msgplus());
}
}
public static void main(String[] args) {
String msg1="hello";
String msg2="bed";
String msg3="java";
msgshow(2,()->{
return msg1+msg2+msg3;//重写接口中的抽象方法
});
}
}
1.使用lambda表达式作为方法的参数:(其实上面的方法就是一个大的演示框架,而下面的
主方法的lambda就相当于往构建好的大框架(接口的实现类)中添加更细致的操作步骤而已)
如果主方法调用的方法,该方法传递进来的参数是一个接口,那么可以:
1主方法中传入的参数可以是:接口的实现类
2主方法中传入的参数可以是:接口的匿名内部类
3如果方法中的参数是函数式接口,则可以使用lambda表达式
代码实现:
package com.bed.hanshushijiekou;
public class ThreadRunable {
public static void startThread(Runnable r){//参数是Runnable接口
new Thread(r).start();//开启多线程
}
public static void main(String[] args) {
//方法1传递匿名内部类(老方法)
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"->"+"线程启动了");
}
});
//方法2使用lambda表达式
startThread(()->{
System.out.println(Thread.currentThread().getName()+"->"+"线程启动了");
});
}
}
2.使用lambda表达式作为方法的返回值:
如果主方法调用的方法,该方法的返回值是一个接口,那么可以:
1可以直接返回:接口的实现类
2可以直接返回:接口的匿名内部类
3如果返回值是函数式接口,则可以使用lambda表达式
案例3 使用自定义比较器对字符组进行比较
package com.bed.hanshushijiekou;
import java.util.Arrays;
import java.util.Comparator;
public class ComparatorReturn {
//因为要改造Comparator,所以方法的返回值是新的Comparator比较器接口
//方法就叫作getComparator
public static Comparator<String> getComparator(){
//111返回值是匿名内部类new Comparator(老方法)
/* return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//按照字符串长度降序排序
return o2.length()-o1.length();
}
};
//222新方法:因为Comparator接口是一个函数式接口,所以使用lambda表达式
return (String o1, String o2)->{return o2.length()-o1.length();};
//333lambda表达式简化*/
return (o1, o2)->o2.length()-o1.length();//对数组长度进行排序
}
public static void main(String[] args) {
String[] arr={"aaa","bbbbb","c","dd"};
Arrays.sort(arr,getComparator());//用我们自己定义的方法对arr进行排序
System.out.println(Arrays.toString(arr));
}
}
第二部分:常用的函数式接口:
1、Supprlier接口:生产型接口,泛型参数传递什么类型,返回值就是什么类型
package com.bed.hanshushijiekou;
import java.util.function.Supplier;
public class getSupplier {
//定义一个方法,参数是Supplier接口
public static String getString(Supplier<String> sup){
return sup.get();//调用Supplier接口中的get方法,此处返回值也是String类型的
}
public static void main(String[] args) {
// 参数是接口,直接使用lambda表达式,重写Supplier中的get方法,使其返回值满足上面方法(String类型)
String s = getString(() -> "bed");
System.out.println(s);
}
}
案例:使用Supplier函数式接口获取数组的最大值:
(其实上面的方法就是一个大的演示框架,而下面的主方法就相当于往构建好的大框架
(接口的实现类、lambda表达式)中添加更细致的操作步骤而已)
package com.bed.hanshushijiekou;
import java.util.function.Supplier;
public class SupplierGetMax {
public static int getmax(Supplier<Integer> sup){
return sup.get();
}
public static void main(String[] args) {
int[] arr={1,677,66,1,5,56,-23};
int mmax=getmax(()->{
int max=arr[0];
for (int i : arr) {
if(i>max){
max=i;
}
}
return max;//这个就是sup.get方法的返回值
});
System.out.println(mmax);
}
}
2、Consumer接口(消费者,使用者):
案例,1Consumer的get方法:使用Consumer来逆转名字
package com.bed.hanshushijiekou.ConsumerPratice;
import java.util.function.Consumer;
public class ConsumerPractice {
public static void getReverse(String name, Consumer<String> con){
con.accept(name);
}
public static void main(String[] args) {
getReverse("baierdong",(String name)->{
String rename=new StringBuffer(name).reverse().toString();
System.out.println(rename);
});
}
}
案例2Consumer的andthen方法:(接力棒操作)
使用Consumer给字符先变成大写,然后改成小写
package com.bed.hanshushijiekou.ConsumerPratice;
import java.util.function.Consumer;
public class ConsumerAndThen {
public static void upAndLow(String s, Consumer<String> con1,Consumer<String> con2){
//先用con1调用accept方法,再使用con2调用accept方法
con1.andThen(con2).accept(s);
}
public static void main(String[] args) {
upAndLow("xiaobaitu",
(s)->{//con1的accept方法
System.out.println(s.toUpperCase());
}, (s)->{//con2的accept方法
System.out.println(s.toLowerCase());
});
}
}
案例3、Consumer的andthen方法:
案例重点:1分两次切割,一次是分开数组,一次是按逗号分开
2注意按逗号拆分后,会变成数组状态,前面的元素顺序为【0】第二位元素
顺序为【1】......往后以此类推。详情见代码。
package com.bed.hanshushijiekou.ConsumerPratice;
import java.util.function.Consumer;
public class FenZuXianShi {
//先用此方法拆分数组,拆成一个个的字符串
public static void chaiFen(String[] main, Consumer<String> con1,Consumer<String> con2){
for (String s : main) {
con1.andThen(con2).accept(s);//在该步骤对拆分好的单个数组s进行操作
}
}
public static void main(String[] args) {
String[] nameage={"bed1,19","bed2,29","bed3,39"};
chaiFen(nameage,
(part)->{
//用[]来把name和age组成为一对;
String name=part.split(",")[0];//按逗号分开后,拿出[0]号位置元素,也就是name
System.out.print("姓名"+name+",");
},
(part)->{
String age=part.split(",")[1]; //按逗号分开后,拿出[1]号位置元素,也就是age
System.out.println("年龄"+age+"。");
});
}
}
2、predicate接口(判断接口):
1.predicate的第一种方法:and(&&)
package com.bed.hanshushijiekou.predicate;
import java.util.function.Predicate;
public class CompareNum {
public static boolean compare(String s, Predicate<String> pre1,Predicate<String> pre2){
//pre1条件和pre2条件是否同时符合
return pre1.and(pre2).test(s);//该语句等于pre1.test(s)&&pre2.test(s)
}
public static void main(String[] args) {
String s="abcdef";
boolean b=compare(s,
(s1)->{
return s.contains("a");
},
(s1)->{
return s.length()>5;
});
System.out.println(b);
}
}
2.predicate的第二种方法:or( | | )
3.predicate的第三种方法:negate( !)
案例1 人员筛选:
//筛选器,筛除大于35岁的女性
package com.bed.hanshushijiekou.predicate;
import java.util.ArrayList;
import java.util.function.Predicate;
public class PersonFilter {
public static ArrayList<String> filter(String[] s, Predicate<String> pre1,Predicate<String> pre2){
//创建一个数组用来接收结果
ArrayList<String> fire=new ArrayList<>();
for (String person : s) {//将数组中的每一组数据拿出来筛选
if(pre1.and(pre2).test(person)){//如果两个条件同时满足
fire.add(person);
}
}
return fire;
}
public static void main(String[] args) {
String[] person={"男,35","女,25","男,25","女,40"};
ArrayList<String> fire=filter(person,
(String p)->{
//按逗号进行分割,判断性别是否为男
String sex = p.split(",")[0];
return sex.equals("女");
},
(String p)->{
//按逗号进行分割,判断年龄是否大于35岁
String s = p.split(",")[1];
Integer i=new Integer(s);//对分隔的字符串进行强制转换
return i>=35;
});
for (String s : fire) {
System.out.println(s);
}
}
}
3.Function接口:转换接口,吃的是草产的是奶
1、Function接口中的apply方法
package com.bed.hanshushijiekou.Function;
import java.util.function.Function;
public class Function1 {
public static void getInt(String str, Function<String,Integer> fun){
Integer apply = fun.apply(str);
System.out.println(apply);
}
public static void main(String[] args) {
String str="12345";
getInt(str,(String s)->{
return Integer.parseInt(s);
});
}
}
1、Function接口中的andthen方法:用来进行组合操作(或是理解为接力棒操作)
package com.bed.hanshushijiekou.Function;
import java.util.function.Function;
//实现 1:先将字符串拆分(String to String)
// 2:将字符串转变为Integer类型 (String to Integer)
// 3:转变后再+10(Integer to Integer)
public class FunctionAndthen {
public static int getInt(String str, //三次转换为用三个FUNCTION接口
Function<String,String> fun1,
Function<String,Integer> fun2,
Function<Integer,Integer> fun3){
return fun1.andThen(fun2).andThen(fun3).apply(str);
}
public static void main(String[] args) {
String str="bed,9";
int age=getInt(str,
(s)->{
return s.split(",")[1];//得到的结果还是String类型
},
(stoi)->{//从上一个Function进行接力棒操作
return Integer.parseInt(stoi);//由String得到Integer
},
(i)->{
return i+20;//接力棒操作
});
System.out.println(age);
}
}