Java8中函数接口有很多,大概有几十个吧,具体究竟是多少我也数不清,所以一开始看的时候感觉一脸懵逼,不过其实根本没那么复杂,毕竟不应该也没必要把一个东西设计的很复杂。
在学习了解之前,希望大家能记住几个单词,掌握这几个单词,什么3,40个官方的函数接口都是小问题了,不信的话接着往下看啦。ok,那这几个单词呢分别是supplier 提供者
,consumer 消费者
,function 函数
,operation 运算符
,binary 二元(就是数学里二元一次方程那个二元,代表2个的意思),双重的
函数接口,你可以理解为对一段行为的抽象,简单点说可以在方法就是将一段行为作为参数进行传递,这个行为呢,可以是一段代码,也可以是一个方法,那你可以想象在java8之前要将一段方法作为参数传递只能通过匿名内部类来实现,而且代码很难看,也很长,函数接口就是对匿名内部类的优化。
??虽然类库中的基本函数接口特别多,但其实总体可以分成四类,就好像阿拉伯数字是无限多的,但总共就10个基本数字一样,理解了这4个,其他的就都明白了。
function,顾名思义,函数的意思,这里的函数是指数学上的函数哦,你也可以说是严格函数语言中的函数,例如haskell里的,他接受一个参数,返回一个值,永远都是这样,是一个恒定的,状态不可改变的方法。其实想讲函数这个彻底将明白可以再开一篇博客了,所以这里不详细的说了。
?? 上面说到,函数接口是对行为的抽象,因此我方便大家理解,就用java中的方法作例子。
Fcuntion接口是对接受一个T类型参数,返回R类型的结果的方法的抽象,通过调用apply方法执行内容。
public class Operation{
/*
下面这个方法接受一个int类型参数a,返回a+1,符合我上面说的接受一个参数,返回一个值
所以呢这个方法就符合Function接口的定义,那要怎么用呢,继续看例子
*/
public static final int addOne(int a){
return a+1;
}
/*
该方法第二个参数接受一个function类型的行为,然后调用apply,对a执行这段行为
*/
public static int oper(int a, Function<Integer,Integer> action){
return action.apply(a);
}
/* 下面调用这个oper方法,将addOne方法作为参数传递 */
pulic static void main(String[] args){
int x = 1;
int y = oper(x,x -> addOne(x));//这里可以换成方法引用的写法 int y = oper(x,Operation::addOne)
System.out.printf("x= %d, y = %d", x, y); // 打印结果 x=1, y=2
/* 当然你也可以使用lambda表达式来表示这段行为,只要保证一个参数,一个返回值就能匹配 */
y = oper(x, x -> x + 3 ); // y = 4
y = oper(x, x -> x * 3 ); // y = 3
}
}
这里的箭头指向的位置就是形参,可以看到第二个箭头的Lambda表达式指向了Funtion接口
Consumer 接口翻译过来就是消费者,顾名思义,该接口对应的方法类型为接收一个参数,没有返回值,可以通俗的理解成将这个参数‘消费掉了‘,一般来说使用Consumer接口往往伴随着一些期望状态的改变或者事件的发生,例如最典型的forEach就是使用的Consumer接口,虽然没有任何的返回值,但是却向控制台输出了语句。
Consumer 使用accept对参数执行行为
public static void main(String[] args) {
Consumer<String> printString = s -> System.out.println(s);
printString.accept("helloWorld!");
//控制台输出 helloWorld!
}
Supplier 接口翻译过来就是提供者,和上面的消费者相反,该接口对应的方法类型为不接受参数,但是提供一个返回值,通俗的理解为这种接口是无私的奉献者,不仅不要参数,还返回一个值,使用get()方法获得这个返回值
Supplier<String> getInstance = () -> "HelloWorld!";
System.out.println(getInstance.get());
// 控偶值台输出 HelloWorld
predicate<T,Boolean> 谓语接口,顾名思义,中文中的‘是’与‘不是’是中文语法的谓语,同样的该接口对应的方法为接收一个参数,返回一个Boolean类型值,多用于判断与过滤,当然你可以把他理解成特殊的Funcation<T,R>,但是为了便于区分语义,还是单独的划了一个接口,使用test()方法执行这段行为
public static void main(String[] args) {
Predicate<Integer> predOdd = integer -> integer % 2 == 1;
System.out.println(predOdd.test(5));
//控制台输出 5
}
介绍完正面这四种最基本的接口,剩余的接口就可以很容易的理解了,java8中定义了几十种的函数接口,但是剩下的接口都是上面这几种接口的变种,大多为限制参数类型,数量,下面举几个例子。
IntPredicate,LongPredicate, DoublePredicate
,这几个接口,都是在基于Predicate接口的,不同的就是他们的泛型类型分别变成了Integer,Long,Double,IntConsumer,LongConsumer, DoubleConsumer
比如这几个,对应的就是Consumer<Integer>,Consumer<Long>,Consumer<Double>
,其余的是一样的道理,就不再举例子了IntToDoubleFunction,IntToLongFunction,
很明显就是对应的Funtion<Integer,Double>
与Fcuntion<Integer,Long>
,其余同理,另外需要注意的是,参数限制与返回值限制的命名唯一不同就是To,简单来说,前面不带To的都是参数类型限制,带To的是返回值类型限制,对于没有参数的函数接口,那显而易见只可能是对返回值作限制。例如LongFunction<R>
就相当于Function<Long,R>
而多了一个To的ToLongFunction<T>
就相当于Function<T,Long>
,也就是对返回值类型作了限制。Binary
的缩写,开头也介绍过这个单词了,是二元的意思,例如BiPredicate,BiFcuntion
等等,而由于java没有多返回值的设定,所以Bi指的都是参数为两个UnaryOperator<T>
一元操作符接口,与BinaryOperator<T>
二元操作符接口,这类接口属于Function接口的简写,他们只有一个泛型参数,意思是Funtion的参数与返回值类型相同,一般多用于操作计算,计算 a + b的BiFcuntion如果限制条件为Integer的话 往往要这么写BiFunction<Integer,Integer,Integer>
前2个泛型代表参数,最后一个代表返回值,看起来似乎是有点繁重了,这个时候就可以用BinaryOperator<Integer>
来代替了。下面是各种类型的接口的示意图,相信只要真正理解了,其实问题并不大
Java8中的lambda表达式,并不是完全闭包,lambda表达式对值封闭,不对变量封闭。简单点来说就是局部变量在lambda表达式中如果要使用,必须是声明final类型或者是隐式的final例如
int num = 123;
Consumer<Integer> print = () -> System.out.println(num);
就是可以的,虽然num没有被声明为final,但从整体来看,他和final类型的变量的表现是一致的,可如果是这样的代码
int num = 123;
num ++;
Consumer<Integer> print = () -> System.out.println(num);
则无法通过编译器,这就是对值封闭(也就是栈上的变量封闭)
如果上文中的num是实例变量或者是静态变量就没有这个限制。
看到这里,自然而然就会有疑问为什么会这样?或者说为什么要这么设计。理由有很多,例如函数的不变性,线程安全等等等,这里我给一个简单的说明
函数式接口(Functional Interface)是Java 8对一类特殊类型的接口的称呼。 这类接口只定义了唯一的抽象方法的接口,并且这类接口使用了@FunctionalInterface
进行注解。在jdk8中,引入了一个新的包java.util.function
, 可以使java 8 的函数式编程变得更加简便。这个package中的接口大致分为了以下四类:
R apply(T t)
void accept(T t)
T get()
boolean test(T t)
本篇介绍了四大函数接口和他们引申出的各类接口,终点是对不同种类行为的封装导致了设计出不同的函数接口,另外在使用函数接口或者lambda表达式的时候,要注意lambda对值封闭这个特性。
java.util.function包中所有的接口整理:
表示一个方法接收参数并返回结果。
Interface | functional method | 说明 |
---|---|---|
Function<T,R> | R apply(T t) | 接收参数类型为T,返回参数类型为R |
IntFunction |
R apply(int value) | 以下三个接口,指定了接收参数类型,返回参数类型为泛型R |
LongFunction |
R apply(long value) | |
Double |
R apply(double value) | |
ToIntFunction |
int applyAsInt(T value) | 以下三个接口,指定了返回参数类型,接收参数类型为泛型T |
ToLongFunction |
long applyAsLong(T value) | |
ToDoubleFunction |
double applyAsDouble(T value) | |
IntToLongFunction | long applyAsLong(int value) | 以下六个接口,既指定了接收参数类型,也指定了返回参数类型 |
IntToDoubleFunction | double applyAsLong(int value) | |
LongToIntFunction | int applyAsLong(long value) | |
LongToDoubleFunction | double applyAsLong(long value) | |
DoubleToIntFunction | int applyAsLong(double value) | |
DoubleToLongFunction | long applyAsLong(double value) | |
UnaryOperator |
T apply(T t) | 特殊的Function,接收参数类型和返回参数类型一样 |
IntUnaryOperator | int applyAsInt(int left, int right) | 以下三个接口,指定了接收参数和返回参数类型,并且都一样 |
LongUnaryOperator | long applyAsInt(long left, long right) | |
DoubleUnaryOperator | double applyAsInt(double left, double right) |
interface | functional method | 说明 |
---|---|---|
BiFunction<T,U,R> | R apply(T t, U u) | 接收两个参数的Function |
ToIntBiFunction<T,U> | int applyAsInt(T t, U u) | 以下三个接口,指定了返回参数类型,接收参数类型分别为泛型T, U |
ToLongBiFunction<T,U> | long applyAsLong(T t, U u) | |
ToDoubleBiFunction<T,U> | double appleyAsDouble(T t, U u) | |
BinaryOperator |
T apply(T t, T u) | 特殊的BiFunction, 接收参数和返回参数类型一样 |
IntBinaryOperator | int applyAsInt(int left, int right) | |
LongBinaryOperator | long applyAsInt(long left, long right) | |
DoubleBinaryOperator | double applyAsInt(double left, double right) |
表示一个方法接收参数但不产生返回值。
interface | functional method | 说明 |
---|---|---|
Consumer |
void accept(T t) | 接收一个泛型参数,无返回值 |
IntConsumer | void accept(int value) | 以下三个类,接收一个指定类型的参数 |
LongConsumer | void accept(long value) | |
DoubleConsumer | void accept(double value) |
interface | functional method | 说明 |
---|---|---|
BiConsumer<T,U> | void accept(T t, U u) | 接收两个泛型参数 |
ObjIntConsumer |
void accept(T t, int value) | 以下三个类,接收一个泛型参数,一个指定类型的参数 |
ObjLongConsumer |
void accept(T t, long value) | |
ObjDoubleConsumer |
void accept(T t, double value) |
返回一个结果,并不要求每次调用都返回一个新的或者独一的结果
interface | functional method | 说明 |
---|---|---|
Supplier |
T get() | 返回类型为泛型T |
BooleanSupplier | boolean getAsBoolean() | 以下三个接口,返回指定类型 |
IntSupplier | int getAsInt() | |
LongSupplier | long getAsLong() | |
DoubleSupplier | double getAsDouble() |
根据接收参数进行断言,返回boolean类型
interface | functional method | 说明 |
---|---|---|
Predicate |
boolean test(T t) | 接收一个泛型参数 |
IntPredicate | boolean test(int value) | 以下三个接口,接收指定类型的参数 |
LongPredicate | boolean test(long value) | |
DoublePredicate | boolean test(double value) | |
BiPredicate<T,U> | boolean test(T t, U u) | 接收两个泛型参数,分别为T,U |
原文:https://www.cnblogs.com/satire/p/14720341.html