1.函数式接口
这样的接口也同时可以用Lambda表达式简化
package Part3.Day_28;
/*
函数式接口:有且只有一个抽象方法的接口,称之为函数式接口
接口中可以包含其他的方法(默认,静态,私有)
*/
@FunctionalInterface //函数式接口,这个注解可以检测这个接口是否是函数式接口
//1.接口中没有抽象方法 2.抽象方法多于一个
public interface MyFunctionalInterface {
public abstract void method();
}
package Part3.Day_28;
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface {
@Override
public void method() {
}
}
package Part3.Day_28;
/*
函数式接口的使用:一般可以作为方法的参数和返回值类型
*/
public class demo {
//定义一个方法,参数使用函数式接口MyFunctionalInterface
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
public static void main(String[] args) {
//调用show方法,方法参数是一个接口,传递接口的实现类
show(new MyFunctionalInterfaceImpl());
//调用show,传递接口的匿名内部类,匿名内部类是会自动产生一个类的
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("使用匿名内部类重写接口中的抽象方法");
}
});
//调用show方法,方法的参数是一个函数式接口,所以我们可以用Lambda表达式,这个不产生类
show(()->{
System.out.println("使用Lambda表达式重写接口方法");
});
}
}
2.Lambda优化日志案例,减少性能浪费
package Part3.Day_28.demo02Lambda;
@FunctionalInterface
public interface MessageBuilder {
//定义一个拼接消息的抽象方法
public abstract String builderMessage();
}
package Part3.Day_28.demo02Lambda;
/*
使用Lambda优化日志案例
(参数类型,参数)->{方法}
Lambda特点:延迟加载
前提:必须存在函数式接口
*/
public class demo02Lambda {
//定义显示日志方法,传递日志等级和messagebuilder接口
public static void showLog(int level, MessageBuilder mb){
//如果是1级则调用MessageBuilder接口中的builderMessage方法
if(level ==1 ){
System.out.println(mb.builderMessage());
}
}
public static void main(String[] args) {
String msg1 = "Hello";
String msg2 = "World";
String msg3 = "Java";
//mb是函数式接口,可以传递Lambda表达式
showLog(1,()->{
return msg1+msg2+msg3;
});
}
/*
使用Lambda表达式作为参数传递,仅仅把参数传到showLog里
只有满足条件才会调用MessageBuilder中的方法builderMessage
才会进行字符串的拼接
如果条件不满足,也就是日志的等级不是1级,
那么MessageBuilder中的方法builderMessage不会执行,不会存在性能浪费
*/
}
3. 函数式接口作为方法的参数案例
package Part3.Day_28.demo02Lambda;
/*
假设java.lang.Runnable作为一个函数式接口
假设有一个startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参
这种情况其实和Thread类的构造方法参数为Runnable一样
*/
public class demo01Runnable {
public static void startThread(Runnable run){
//开启多线程
new Thread(run).start();
}
public static void main(String[] args) {
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程启动了1");
}
});
startThread(()->{
System.out.println(Thread.currentThread().getName()+"线程启动了2");
});
//优化Lambda表达式
startThread(()->
System.out.println(Thread.currentThread().getName()+"线程启动了3"));
}
}
输出为:
Thread-2线程启动了3
Thread-0线程启动了1
Thread-1线程启动了2
或者:
Thread-2线程启动了3
Thread-1线程启动了2
Thread-0线程启动了1
4.函数式接口作为方法的返回值类型
package Part3.Day_28.demo03Lambdatest;
import java.util.Arrays;
import java.util.Comparator;
public class demo02Comparator {
public static Comparator getComparator(){
/*//方法的返回值是一个接口,我们可以返回这个接口的匿名内部类
return new Comparator() {
@Override
public int compare(String o1, String o2) {
//按照字符串的降序排序
return o2.length()-o1.length();
}
};*/
//return (String o1, String o2)->{return o2.length()-o1.length();};
//省略写法:
return (o1, o2)-> o2.length()-o1.length();
}
public static void main(String[] args) {
String[] array = {"aaaa","bb","c"};
//输出排序前数组
System.out.println(Arrays.toString(array));
//排序后
Arrays.sort(array,getComparator());
System.out.println(Arrays.toString(array));
}
}
5.常用的函数式接口
java.util.function包里
(1). Supplier接口
Supplier接口练习:求数组中元素的最大值
package Part3.Day_28.demo04Supplier;
import java.util.Arrays;
import java.util.function.Supplier;
public class demo02test {
public static int maxx(Supplier function){
return function.get();
}
public static void main(String[] args) {
int[] arr = {1,2,5,8,9};
int m = maxx(()->{
Arrays.sort(arr);
int max = arr[arr.length-1];
return max;
});
System.out.println(m);
}
}
(2) Consumer接口 :就是使用这个同类型的数据
字符串反转案例:
package Part3.Day_28.demo04Supplier;
public class test {
public static void main(String[] args) {
String a = "赵丽颖";
System.out.println(new StringBuilder(a).reverse().toString());
System.out.println(new StringBuffer(a).reverse().toString());
}
}
Consumer接口还有一个默认方法:
简写:
打印名字练习:
package Part3.Day_28.demo05Consumer;
import java.util.function.Consumer;
public class demo01test {
public static void main(String[] args) {
String[] array = {"迪丽热巴,女","古力娜扎,女","马儿扎哈,男"};
for (String s : array) {
method(s,(t)-> System.out.print("姓名:"+s.split(",")[0]+" "),
(x)-> System.out.println("性别:"+s.split(",")[1]));
}
}
public static void method(String s, Consumer con1,Consumer con2){
con1.andThen(con2).accept(s);
}
}
(3) Predicate接口
Predicate接口中有三个默认方法
第一个方法:and 相当于与运算符
相当于判断必须两个与,返回结果。方法内部的两个判断条件也是用&&链接起来的
判断一个字符串是否包含某个子字符串: str.contains("a");
第二个方法: or 相当于 || 符号
第三个方法:negate 相当于取反符号!
集合信息筛选练习:
package Part3.Day_28.demo06Predicate;
import java.util.ArrayList;
import java.util.function.Predicate;
public class demo01test {
public static void main(String[] args) {
String[] array = {"迪丽热巴,女","古力娜,女","马儿扎哈,男"};
ArrayList ans = filter(array,(s)-> s.split(",")[0].length()==4,
(s)-> s.split(",")[1].equals("女")
);
for (String an : ans) {
System.out.println(an);
}
}
public static ArrayList filter(String[] arr, Predicate p1,Predicate p2){
ArrayList ans = new ArrayList<>();
for (String s : arr) {
boolean x = p1.and(p2).test(s);
if (x){
ans.add(s);
}
}
return ans;
}
}
(4) Function接口