Java基础篇 - 函数式接口

131 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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

后记

喜欢我的文章的朋友点点喜欢、收藏,也欢迎朋友们评论区留下你的意见和建议,恕毅在此拜谢!