开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
前言
在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。以创建线程为例,我们真的希望创建一个匿名内部类对象吗?不。我们只是为了做这件事情而不得不创建一个对象。我们真正希望做的事情是:将run方法体内的代码传递给Thread类知晓。传递一段代码——这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。那,有没有更加简单的办法?如果我们将关注点从“怎么做”回归到“做什么”的本质上,就会发现只要能够更好地达到目的,过程与形式其实并不重要。
一、函数式接口
函数式接口是指只包含一个抽象方法的接口,你可以通过Lambda表达式来创建该接口的对象。另外,我们也可以自定义函数式接口,我们在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。
二、@FunctionalInterface注解
@FunctionalInterface 注解用来标识某个接口是函数式接口(所谓函数式接口就是指对于一个接口只能有一个抽象方法。这种类型的接口也称为SAM(Single Abstract Method)接口)。@FunctionalInterface注解Java中的定义代码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
//Target表明FunctionalInterface只能用来修饰接口、类和枚举
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
FunctionalInterface 注解只能作用于接口,该注解主要用于编译级错误检查。使用@FunctionalInterface注解修饰接口后,如果写的接口不符合函数式接口规范,则编译器会报错。 正确示例如下:
@FunctionalInterface
public interface CustomInferface {
void test();
}
错误示例如下:
@FunctionalInterface
public interface CustomInferface {
void test1();
void test2();
}
上述示例会有如下编译异常提示:
Multiple non-overriding abstract methods found in interface xxxInferface
三、JAVA内置核心函数式接口
在学习lambda表达式的时候,我们知道,要使用lambda表达式,我们就要创建一个函数式接口,那每次用lambda表达式的时候岂不是很麻烦,这时候,java在java.util.function 包下面给我们内置了核心函数式接口。
3.1 Function<T,R>:函数型接口
Function:一个参数且有返回值 Function接口声明了一个可接收一个参数且有返回值的方法。源码如下:
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*可以可以
* @param t the function argument
* @return the function result
*/
R apply(T t);
...
}
如果需要指定参数或返回值的类型,则可使用Function接口的衍生接口,如
- IntFunction(指定入参是整数)
- DoubleFunction(指定入参是浮点数)
- ToLongFunction(指定返回值是长整数)
- ToDoubleFunction(指定返回值是浮点数)
- DoubleToIntFunction(指定入参是浮点数、返回值是整数)
- IntToDoubleFunction(指定入参是整数、返回值是浮点数)
3.2 BiFunction<T, U, R>函数型接口
BiFunction:两个参数且有返回值 BiFunction接口声明了一个可接收两个参数且有返回值的方法。源码如下:
@FunctionalInterface
public interface BiFunction<T, U, R> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);
...
}
如果需要指定参数或返回值的类型,则可使用类似Function接口的衍生接口,如
- ToIntBiFunction
- ToLongBiFunction
- ToDoubleBiFunction等
与Function接口不同的是,BiFunction没有指定入参类型的衍生接口。
3.3 Supplier:供给型接口
Supplier:无参但有返回值 Supplier接口声明了一个无参但有返回值的方法。源码如下:
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
如果需要指定返回值的类型,则可像Function接口一样,使用Supplier衍生接口,如
- IntSupplier
- LongSupplier
- DoubleSupplier
3.4 Consumer:消费型接口
Consumer:一个参数但无返回值 Consumer接口声明了一个参数但无返回值的方法。源码如下:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
如果需要指定入参的类型,则可像Function接口一样,使用Consumer衍生接口,如
- IntConsumer
- LongConsumer
- DoubleConsumer
3.5 Predicate:断言型接口
Predicate:一个参数且返回boolean值 Predicate接口声明了一个参数且返回值是boolean的方法。源码如下:
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
...
}
类似地,BiPredicate接口声明了两个参数且返回值是boolean的方法。同时,如果需要指定入参的类型,则可像Function接口一样,使用Predicate衍生接口,如
- IntPredicate
- LongPredicate
- DoublePredicate
3.6 XxxOperator:参数和返回值相同类型的接口
XxxOperator:参数和返回值相同类型 XxxOperator表示一类接口,这类接口均声明了参数和返回值类型相同的方法。这里给出参数和返回值类型相同,且入参是一个的接口的源码:
@FunctionalInterface
public interface IntUnaryOperator {
/**
* Applies this operator to the given operand.
*
* @param operand the operand
* @return the operator result
*/
int applyAsInt(int operand);
}
类似地,XxxBinaryOperator接口声明了参数和返回值相同类型,且参数是两个的方法。同时,如果需要指定参数或返回值的类型,则可像Function接口一样,使用XxxOperator或XxxBinaryOperator衍生接口,如 LongUnaryOperator DoubleUnaryOperator LongBinaryOperator DoubleBinaryOperator
后记
喜欢我的文章的朋友点点喜欢、收藏,也欢迎朋友们评论区留下你的意见和建议,恕毅在此拜谢!