函数式接口
1.概述
1.1 定义
函数式接口:有且仅有一个抽象方法的接口
Java中的函数式接口体现就是Lambda表达式,所以函数式接口就是可以使用Lambda表达式的接口
只有确保接口中有且仅有一个抽象方法,Java中Lambda表达式才能顺利进行推导
1.2 使用
如何检测一个接口是否为函数式接口?
- @FunctionalInterface
- 放在定义接口的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
注意:
- 我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要满足函数式接口定义的条件,也同样是函数式接口。但是,建议加上该注解
//函数式接口:有且仅有一个抽象方法的接口
public class MyInterfaceDemo {
public static void main(String[] args) {
MyInterface my = () -> System.out.println("函数式接口");
my.show();//函数式接口
}
}
@FunctionalInterface
interface MyInterface {
void show();
// void test();
}
2.函数式接口作为参数
需求:
- 定义一个类(RunnableDemo),在类中提供两个方法
- 一个方法是:startThread(Runnable r) 方法参数Runnable是一个函数式接口
- 一个是主方法,在主方法中调用startThread方法
public class RunnableDemo {
public static void main(String[] args) {
//在主方法中调用startThread方法
//匿名内部类
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程启动了");
}
});
//Lambda表达式
startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));
}
private static void startThread(Runnable r) {
// Thread t = new Thread(r);
// t.start();
new Thread(r).start();
}
}
通过上面练习,我们知道:
如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递
-
startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));
3.函数式接口作为方法返回值
需求:
- 定义一个类(ComparatorDemo),在类中提供两个方法
- 一个方法是:Comparator getComparator() 方法返回值Comparator是一个函数式接口
- 一个是主方法,在主方法中调用getComparator()方法
package com.advanced.functionalinterface.demo03;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class ComparatorDemo {
public static void main(String[] args) {
//构造场景
ArrayList<String> arr = new ArrayList<String>();
//向集合中添加元素
arr.add("cccc");
arr.add("bb");
arr.add("aaa");
arr.add("d");
//排序前
System.out.println("排序前:"+arr);//排序前:[cccc, bb, aaa, d]
//使用工具类自然排序
// Collections.sort(arr);//排序后:[aaa, bb, cccc, d]
//使用自定义比较器排序
Collections.sort(arr,getComparator());//排序后:[d, bb, aaa, cccc]
//排序后
System.out.println("排序后:"+arr);
}
private static Comparator<String> getComparator() {
//匿名内部类
// return new Comparator<String>() {
// @Override
// public int compare(String s1, String s2) {
// return s1.length()-s2.length();
// }
// };
//Lambda表达式
// return (String s1,String s2) -> {
// return s1.length()-s2.length();
// };
//Lambda简化式
return (s1,s2) -> s1.length()-s2.length();
}
}
通过上面练习,我们知道:
如果方法的返回值是一个函数式接口,我们可以使用Lambda表达式作为结果返回
-
private static Comparator<String> getComparator() { return (s1,s2) -> s1.length()-s2.length(); }
4.常用的函数式接口
4.1 内容
Java8在java.util.function包下预定义了大量的函数式接口供我们使用
我们重点学习下面的4个接口:
- Supplier接口
- Consumer接口
- Predicate接口
- Function接口
4.2 Supplier接口
- public interface Supplier:包含一个无参的方法
- T get():获得结果
- 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
- Supplier接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
package com.advanced.functionalinterface.demo04supplier;
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
String s = getString(() -> "林青霞");
System.out.println(s);
Integer i = getInteger(() -> 30);
System.out.println(i);
}
private static Integer getInteger(Supplier<Integer> i) {
return i.get();
}
private static String getString(Supplier<String> supp) {
return supp.get();
}
}
练习:
- 定义一个类(SupplierTest),在类中提供两个方法
- 一个方法是int getMax(Supplier sup) 返回int数组中的最大值
- 一个是主方法,在主方法中调用getMax方法
package com.advanced.functionalinterface.demo04supplier;
import java.util.function.Supplier;
public class SupplierTest {
public static void main(String[] args) {
//定义一个int[]数组
int[] arr = {
10, 90, 30, 40, 20, 50};
int max = getMax(() -> {
int oldmax = arr[0];
for (int i = 0; i < arr.length; i++) {
if (oldmax < arr[i]) {
oldmax = arr[i];
}
}
return oldmax;
});
System.out.println(max);
}
//返回int数组中的最大值
public static int getMax(Supplier<Integer> sup) {
return sup.get();
}
}
4.3 Consumer接口
- public interface Consumer:包含两个方法
- void accept(T t): 对给定的参数执行此操作
- default Consumer andThen(Consumer<? super T> after):返回一个组合的Consumer,按顺序执行该操作,然后执行after操作
- Consumer接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
package com.advanced.functionalinterface.demo05consumer;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
// operatorString((s) -> {
// System.out.println(s);
// });
operatorString(s -> System.out.println(s));//林青霞
// operatorString(System.out::println);
operatorString(s -> System.out.println(new StringBuilder(s).reverse().toString()));//霞青林
System.out.println("==========");
operatorString("林青霞",s -> System.out.println(s),s -> System.out.println(new StringBuilder(s).reverse().toString()));
}
//定义一个方法,用不同的方式消费同一个字符串两次
public static void operatorString(String name,Consumer<String> con1,Consumer<String> con2) {