引言
在java中是指:有且仅有一个抽象方法的接口。当然接口中也可以有其他方法(默认、静态、私有)
Java8所有的新特性基本基于函数式编程的思想,函数式编程的带来,给Java注入了新鲜的活力。函数式编程的几个特点:
- 函数可以作为变量、参数、返回值和数据类型。
- 基于表达式来替代方法的调用
- 函数无状态,可以并发和独立使用
- 函数无副作用,不会修改外部的变量
- 函数结果确定性;同样的输入,必然会有同样的结果。
- 函数式接口,即适用于函数式编程场景的接口。而java中的函数式编程体现就是
Lambda
,所以函数式接口就是可 以适用于Lambda
使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda
才能顺利地进行推导。
@FunctionalInterface注解
作用:可以检测接口是否是一个函数式接口
是:编译成功
否:编译失败(接口中没有抽象方法或者抽象方法个数大于1)
函数式编程
有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费。而Lambda表达式是延迟执行的,这正好可以 作为解决方案,提升性能。
public class Demo01 {
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
public static void main(String[] args) {
//调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
show(new MyFunctionalInterfaceImpl());
//调用show方法,方法的参数是一个接口,所以我们可以传递接口的匿名内部类
//out文件夹中会产生一个Demo01$1.class文件
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("使用匿名内部类重写接口中的抽象方法");
}
});
//调用show方法,方法的参数是一个函数式接口,所以我们可以使用Lambda表达式
//不会产生.class文件
show(()->{
System.out.println("使用Lambda表达式重写接口中的抽象方法");
});
//简化Lambda表达式
show(()->System.out.println("使用简化Lambda表达式重写接口中的抽象方法"));
}
}
从应用层面来讲,Java中的Lambda
可以被当做是匿名内部 类的“语法糖”,但是二者在原理上是不同的。 (Lambda表达式不会产生.class文件)
常用的函数式编程
JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function
包中被提供。
Supplier接口
java.util.function.Supplier 接口仅包含一个无参的方法: T get()
。用来获取一个泛型参数指定类型的对象数据。
Supplier接口被称之为生成型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据。
public class Demo01Supplier {
public static String getString(Supplier<String> sp){
return sp.get();
}
public static void main(String[] args) {
//调用getString方法,参数Supplier<String>是一个函数式接口,所以可以用lambda表达式
String s=getString(()->{return "hello World";});
System.out.println(s);
//优化lambda表达式
String s1=getString(()->"hello world");
System.out.println(s);
}
}
Consumer接口
java.util.function.Consumer<T>
接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定。
泛型指定什么类型,就可以使用accept方法消费什么类型的数据,至于怎么消费,需要自定义(输出,计算…)
public class Demo01Consumer {
public static void method(String name, Consumer<String>con){
con.accept(name);
}
public static void main(String[] args) {
method("李小明",(name)->{
//消费方式:把字符串进行翻转输出
StringBuffer reName=new StringBuffer(name).reverse();
System.out.println(reName);
});
}
}
还有一个值得注意的是他的andThen
方法,它是它是Consumer接口的默认方法
作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,对数据进行消费
Consumer<String> con1;
Consumer<String> con2;
String s="hello";
con1.accept(s);
con2.accept(s);//s被消费了两次
//连接两个Consumer接口,再进行消费,谁写下前面谁先消费
con1.andThen(con2).accept(s);
Predicate接口
java.util.function.Predicate<T>
接口。
作用:对某种数据类型的数据进行判断,结果返回一个boolean值
Predicate接口中包含一个抽象方法:
Boolean test(T t): 对指定数据类型的数据进行判断
public class Demo01Predicate {
public static boolean checkString(String s,Predicate<String> pre){
return pre.test(s);
}
public static void main(String[] args) {
String s="sdffds";
//调用checkString方法对字符串进行校验,参数传递字符串和Lambda表达式
// boolean b = checkString(s, (str) -> {
// //判断字符串的长度是否大于5
// return str.length()>5;
// });
//优化lambda表达式
boolean b = checkString(s, str -> str.length()>5);
System.out.println(b);
}
}
Predicate接口中三种默认方法and,or,negate
(分别具有与或非的作用)分别在接口函数使用:
public static boolean checkString(String s,Predicate<String> pre1,Predicate<String> pre2){
return pre1.and(pre2).test(s);//与方法
public static boolean checkString(String s,Predicate<String> pre1,Predicate<String> pre2){
return pre1.or(pre2).test(s);//或方法
public static boolean checkString(String s,Predicate<String> pre){
return pre.negate().test(s);//取反方法
Function接口
java.util.function.Function<T,R>
接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。(相当于数学中y=f(x),称x->y的映射)
Function接口最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果,使用场景例如:将String类型转换为Integer类型。
Function接口的默认方法andThen:用来进行组合操作。
下面是使用Function进行函数拼接,将字符串中的数字字符串先转换成integer型,在将其+100,最后输出。
public class Demo03FunctionPractice {
public static int change(String s,
Function<String,String> fun1,
Function<String,Integer>fun2,
Function<Integer,Integer>fun3)
{
int result = fun1.andThen(fun2).andThen(fun3).apply(s);
return result;
}
public static void main(String[] args) {
String str="小明,18";
int result = change(str,
(String s) ->
{
return s.split(",")[1];
},
(String s) ->
{
return Integer.parseInt(s);
},
(Integer i) ->
{
return i + 100;
});
System.out.println(result);
}
}