- JDK1.8中引入了用于函数式编程的支持。java中的函数式接口指:有且只有一个方法的接口。函数式接口是适用于函数式编程场景的接口。而java中的函数式编程指的就是Lamda,所以函数式接口就是可以适用于Lamda使用的接口。只要确保接口中有且仅有一个抽象方法,java中的Lamda才能顺利推导。
Java官方专门提供了@FunctionalInterface注解用于确保接口中只有一个方法,比如自定义一个函数式接口,当然如果一个接口符合函数式编程规范(及接口中只有一个方法)即可,因此不加此注解也是可以的,@FunctionalInterface注解只是起到强制检查的作用。
@FunctionalInterface
public interface Function{
void method(String str);
}
Java中的Lamda可以被当作匿名内部类的替代写法,但是两者的底层实现原理是不同的。
public class Demo {
private static void method(String str, Function<String> lambda) {
lambda.method(str);
}
public static void main(String[] args) {
method("张三",s -> System.out.println(s) );
}
}
Lamda表达式简化了传统java编码的写法就比如集合的排序可以这么写
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(42);
list.add(52);
list.add(7);
list.add(48);
list.add(99);
list.add(5);
Collections.sort(list,(a,b) -> a-b);
System.out.println("list = " + list);
- JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function 包中被提供。 下面是简单的几个接口及使用示例。
2.1 Supplier接口
当Lamdba表达式需要“对外提供”一个符合泛型类型的对象数据,可以使用该接口
private static int getMax(Supplier<Integer> fun){
return fun.get();
}
public static void main(String[] args) {
// 求数组最大值
int arr[] = {2,3,4,52,333,23};
int max = getMax(() -> {
int maxV =arr[0];
for (int i =1; i<arr.length;i++){
int val =arr[i];
if(val > maxV){
maxV = val;
}
}
return maxV;
});
}
2.2 Consum接口
java.util.function.Consumer<T> 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定。
private static void consumString(Consumer<String> fun){
fun.accept("I am EmonH");
}
public static void main(String[] args) {
consumStrings(s -> System.out.println("s = " + s.toLowerCase()));
}
默认方法:andThen
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作, 然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 。
private static void consumStrings(Consumer<String> fun1,Consumer<String> fun2){
fun1.andThen(fun2).accept("I am EmonH");
}
public static void main(String[] args) {
consumStrings(s -> System.out.println("s = " + s.toLowerCase()),
s -> System.out.println("s = " + s.toUpperCase()));
}
2.3 Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用 java.util.function.Predicate<T> 接口。其默认方法有test,and,or,negate
private static void predicateInteger1(Predicate<Integer> fun1){
boolean ispositiveNum = fun1.test(2) && fun1.test(4);
System.out.println(ispositiveNum ?"是" :"否");
}
// 并
private static void predicateInteger2(Predicate<Integer> fun1,Predicate<Integer> fun2){
boolean ispositiveNum = fun1.test(2) && fun2.test(2);
System.out.println(ispositiveNum ?"是" :"否");
}
// 并
private static void predicateInteger3(Predicate<Integer> fun1,Predicate<Integer> fun2){
boolean ispositiveNum = fun1.and(fun2).test(2);
System.out.println(ispositiveNum ?"是" :"否");
}
// 或
private static void predicateInteger4(Predicate<Integer> fun1,Predicate<Integer> fun2){
boolean ispositiveNum = fun1.or(fun2).test(2);
System.out.println(ispositiveNum ?"是" :"否");
}
// 取反
private static void predicateInteger5(Predicate<String> fun1){
boolean ispositiveNum = fun1.negate().test("EmonH");
System.out.println(ispositiveNum ?"是" :"否");
}
public static void main(String[] args) {
predicateInteger1(s -> s >4);
predicateInteger2(s -> s ==4,s -> s ==4);
predicateInteger3(s -> s ==4,s -> s ==4);
predicateInteger4(s -> s ==4,s -> s ==4);
predicateInteger5(s -> s.length() >4);
}
2.4 Function接口
java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件, 后者称为后置条件。
// Function 接口中主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果。
// 使用的场景例如:将 String 类型转换为 Integer 类型。
private static void method(Function function,String str){
Integer num = function.apply(str);
System.out.println("num = " + num);
}
// 默认方法:andThen
// Function 接口中有一个默认的 andThen 方法,用来进行组合操作。
private static void method2(Function function,Function function2,String str){
Integer num = function.andThen(function2).apply(str);
System.out.println("num = " + num);
}
public static void main(String[] args) {
String str ="12356";
method(s->Integer.parseInt(s),str);
String str2 ="赵丽颖,20";
method2(s->Integer.parseInt(s),i-> i*100,str2.split(",")[1]);
}