首页 > 应用开发 > Java > java8 新特性之函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
如定义了一个函数式接口如下:
@FunctionalInterfaceinterface GreetingService
{ void sayMessage(String message);
}那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):
GreetingService greetService1 = message -> System.out.println("Hello " + message);java.util.function 它包含了很多类,用来支持 Java的 函数式编程,该包中的函数式接口有(对于英文不好的我,这个表格也算是照抄下来了):
| 序号 | 接口 & 描述 |
|---|---|
| 1 |
BiConsumer<T,U>
代表了一个接受两个输入参数的操作,并且不返回任何结果 |
| 2 |
BiFunction<T,U,R>
代表了一个接受两个输入参数的方法,并且返回一个结果 |
| 3 |
BinaryOperator<T>
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 |
| 4 |
BiPredicate<T,U>
代表了一个两个参数的boolean值方法 |
| 5 |
BooleanSupplier
代表了boolean值结果的提供方 |
| 6 |
Consumer<T>
代表了接受一个输入参数并且无返回的操作 |
| 7 |
DoubleBinaryOperator
代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
| 8 |
DoubleConsumer
代表一个接受double值参数的操作,并且不返回结果。 |
| 9 |
DoubleFunction<R>
代表接受一个double值参数的方法,并且返回结果 |
| 10 |
DoublePredicate
代表一个拥有double值参数的boolean值方法 |
| 11 |
DoubleSupplier
代表一个double值结构的提供方 |
| 12 |
DoubleToIntFunction
接受一个double类型输入,返回一个int类型结果。 |
| 13 |
DoubleToLongFunction
接受一个double类型输入,返回一个long类型结果 |
| 14 |
DoubleUnaryOperator
接受一个参数同为类型double,返回值类型也为double 。 |
| 15 |
Function<T,R>
接受一个输入参数,返回一个结果。 |
| 16 |
IntBinaryOperator
接受两个参数同为类型int,返回值类型也为int 。 |
| 17 |
IntConsumer
接受一个int类型的输入参数,无返回值 。 |
| 18 |
IntFunction<R>
接受一个int类型输入参数,返回一个结果 。 |
| 19 |
IntPredicate
:接受一个int输入参数,返回一个布尔值的结果。 |
| 20 |
IntSupplier
无参数,返回一个int类型结果。 |
| 21 |
IntToDoubleFunction
接受一个int类型输入,返回一个double类型结果 。 |
| 22 |
IntToLongFunction
接受一个int类型输入,返回一个long类型结果。 |
| 23 |
IntUnaryOperator
接受一个参数同为类型int,返回值类型也为int 。 |
| 24 |
LongBinaryOperator
接受两个参数同为类型long,返回值类型也为long。 |
| 25 |
LongConsumer
接受一个long类型的输入参数,无返回值。 |
| 26 |
LongFunction<R>
接受一个long类型输入参数,返回一个结果。 |
| 27 |
LongPredicate
R接受一个long输入参数,返回一个布尔值类型结果。 |
| 28 |
LongSupplier
无参数,返回一个结果long类型的值。 |
| 29 |
LongToDoubleFunction
接受一个long类型输入,返回一个double类型结果。 |
| 30 |
LongToIntFunction
接受一个long类型输入,返回一个int类型结果。 |
| 31 |
LongUnaryOperator
接受一个参数同为类型long,返回值类型也为long。 |
| 32 |
ObjDoubleConsumer<T>
接受一个object类型和一个double类型的输入参数,无返回值。 |
| 33 |
ObjIntConsumer<T>
接受一个object类型和一个int类型的输入参数,无返回值。 |
| 34 |
ObjLongConsumer<T>
接受一个object类型和一个long类型的输入参数,无返回值。 |
| 35 |
Predicate<T>
接受一个输入参数,返回一个布尔值结果。 |
| 36 |
Supplier<T>
无参数,返回一个结果。 |
| 37 |
ToDoubleBiFunction<T,U>
接受两个输入参数,返回一个double类型结果 |
| 38 |
ToDoubleFunction<T>
接受一个输入参数,返回一个double类型结果 |
| 39 |
ToIntBiFunction<T,U>
接受两个输入参数,返回一个int类型结果。 |
| 40 |
ToIntFunction<T>
接受一个输入参数,返回一个int类型结果。 |
| 41 |
ToLongBiFunction<T,U>
接受两个输入参数,返回一个long类型结果。 |
| 42 |
ToLongFunction<T>
接受一个输入参数,返回一个long类型结果。 |
| 43 |
UnaryOperator<T>
接受一个参数为类型T,返回值类型也为T。 |
菜鸟教程的示例略
代表了一个接受两个输入参数的操作,并且不返回任何结果
// 想不到更好的示例了,就测试一下 BiConsumer 应该一次性单独逻辑,不依赖的eval2(list, (k,v) -> {System.out.println("传入的参数1为:"+k + " 传入的参数2为:"+v);});public static void eval2(List<Integer> list, BiConsumer<Integer,String> biConsumer) { for(Integer n: list) {biConsumer.accept(n,"pa2");}
}输出结果为:
传入的参数1为:1 传入的参数2为:pa2 传入的参数1为:2 传入的参数2为:pa2 传入的参数1为:3 传入的参数2为:pa2 传入的参数1为:4 传入的参数2为:pa2 传入的参数1为:5 传入的参数2为:pa2 传入的参数1为:6 传入的参数2为:pa2 传入的参数1为:7 传入的参数2为:pa2 传入的参数1为:8 传入的参数2为:pa2 传入的参数1为:9 传入的参数2为:pa2
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
// 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 // 逻辑处理,并返回与参数类型一样的结果eval3(list, (k,v) -> v+k);public static void eval3(List<Integer> list, BinaryOperator<String> binaryOperator) { for(Integer n: list) {System.out.println(binaryOperator.apply(String.valueOf(n),"abc"));}
}
这个方法泛型只有一个,却要传递两个参数。结果如下:
abc1 abc2 abc3 abc4 abc5 abc6 abc7 abc8 abc9
代表了一个两个参数的boolean值方法
// BiPredicate<T,U> 方法介绍:代表了一个两个参数的boolean值方法// 处理逻辑并返回boolean类型,可穿两个不同类型参数。eval4(list, (k,v) -> v.length()==k);public static void eval4(List<Integer> list, BiPredicate<Integer,String> biPredicate) { for(Integer n: list) {System.out.println(biPredicate.test(n,"213"));}
}
这个可以传入两个不同的类型进行对比,返回boolean类型。结果如下:
falsefalsetruefalsefalsefalsefalsefalsefalse
代表了一个接受两个输入参数的方法,并且返回一个结果
// BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果// 三个类型都可自定义,相当于处理两个参数后返回结果。eval5(list, (k,v) -> v.length()==k);public static void eval5(List<Integer> list, BiFunction<Integer,String,Boolean> biFunction) { for(Integer n: list) {System.out.println(biFunction.apply(n,"213"));}
}
结果如下:
falsefalsetruefalsefalsefalsefalsefalsefalse
代码没有具体含义,只是学习一下,其实只要看几个大概就能理解这个函数式接口的大概逻辑了。
有一些自带的函数式接口,除了唯一的一个抽象方法,还有一些默认方法,还是很好的。可以看下源码,暂时无业务需求。
贴上完整的练习代码如下:
FunctionInterface
写完函数式接口,有个疑问函数式接口和抽象类有啥区别?除了接口和函数的区别,还有那些区别。以下摘自知乎,还不是很能说服自己。
在 java 8 之前,接口与其实现类之间的 耦合度 太高了( tightly coupled),当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法解决了这个问题,它可以为接口添加新的方法,而不会破坏已有的接口的实现。这在 lambda 表达式作为 java 8 语言的重要特性而出现之际,为升级旧接口且保持向后兼容(backward compatibility)提供了途径。
this,没有构造函数,不能拥有实例字段(实例变量)或实例方法,无法保存
状态(
state),抽象方法中可以。函数式接口里是可以包含静态方法,因为静态方法不能是抽象方法,是一个已经实现了的方法,所以是符合函数式接口的定义的;
3、 函数式接口里允许定义 java.lang.Object 里的 public 方法
函数式接口里是可以包含Object里的public方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法);因为任何一个函数式接口的实现,默认都继承了 Object 类,包含了来自 java.lang.Object 里对这些抽象方法的实现;
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69992808/viewspace-2750554/ ,如需转载,请注明出处,否则将追究法律责任。