Java基础篇 - 函数式接口

简介: Java基础篇 - 函数式接口

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

后记

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


相关文章
|
6天前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
26 7
|
6天前
|
前端开发 JavaScript Java
【前端学java】Java中的接口和枚举概念(8)
【8月更文挑战第9天】Java中的接口和枚举概念(8)
23 4
|
4天前
|
Oracle 安全 Java
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
|
10天前
|
存储 算法 Oracle
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
38 8
|
10天前
|
数据采集 Java API
java接口防爬虫
8月更文挑战第9天
|
10天前
|
安全 算法 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(下)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
47 6
|
10天前
|
存储 安全 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(中)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
51 5
|
10天前
|
Java 关系型数据库 程序员
11 Java接口(语法、规范、微观&宏观接口)
11 Java接口(语法、规范、微观&宏观接口)
31 6
|
10天前
|
存储 安全 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(上)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
42 3
|
11天前
|
Java API 开发者
探索Java中的Lambda表达式和函数式接口
【8月更文挑战第8天】 在Java 8中引入的Lambda表达式,不仅简化了代码编写,也提高了程序的可读性和性能。本文将深入探讨Lambda表达式的工作原理以及如何通过函数式接口来实现更简洁、高效的编程模式。