jdk1.8之函数式接口

news2024/11/30 8:39:11

l@[TOC]

函数式接口概述

    jdk1.8 引入了一个核心概念:函数式接口(Functional Interface)。如果一个接口有且只有一个未实现的方法,那这个接口就称为函数式接口。并且引入了一个新的注解:@FunctionalInterface , 把这个注解放到接口定义之前,就表明这个接口是一个函数式接口,编译器会检查该接口是否只有一个未实现的方法,如果定义了多个或者没有定义,编译则会报错。
    不过这个注解不是必须的,就算没有加这个注解,虚拟机也能识别出函数式接口。这个注解按我的理解,主要是为了防止误操作,加了这个注解之后接口就不会允许出现多个未实现方法了。

Lambda 表达式

函数式接口最大的一个特点是:可以用Lambda实例化它们。Lambda表达式能够让你将函数作为一个方法参数进行传递。Lambda在代码简洁性和可读性方面带来了极大的提升,在1.8之前像匿名内部类,事件监听器的写法都非常冗长,可读性差。Lambda使代码更加紧凑。

Lambda的组成

Lambda表达式由3部分组成:
一是被括号包裹的以逗号分隔的参数列表,参数即接口的唯一方法的参数;
例如: () 或者 (param1, param2)
二是一个箭头符号: ->
三是方法体,方法体可以是表达式和代码块。语法如下:
方法体为表达式:该表达式的值作为方法的返回值

(param) -> expression

方法体为代码块,需要用{}包裹起来,并且需要加一个return 作为方法返回值,如果方法不需要返回值,则不需要return

(param) -> {statements;}

在jdk之前, 事件监听器的实现一般是这样:

button.addListener(
	new ActionListener(){
		@Override
		public void perform(ActionEvent){
			Systen.out.println("old ways");
		}
	}
)

Lambda表达式简化写法:
button.addListener((event)->Systen.out.println(“lambda ways”));

函数式接口和lambda表达式是函数式编程的基础。每个Lambda都对应一个函数式接口。我们可以直接使用Lambda而不用为每个Lambda表达式自定义一个函数式接口,是因为jdk8为我们提供了许多常用的函数式接口:Function , Consumer, Supplier, Predicate。

函数式接口: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);

    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

R apply(T t) 就是这个接口的唯一未实现方法,Lambda表达式也就是实现了这个方法。另外有2个方法比较难理解: compose(Function before) 和 andThen(Function after)
这两个方法是为了函数式接口的复合使用,类似与 f(g(x))。 这意味着可以把多个简单的Lambda复合成复杂的表达式

使用示例:

	  public static void main(String[] args) {
         Function<Integer,Integer> f = (i)-> {return i+1;};
         Function<Integer,Integer> g = (x) -> {return x*2;};
         Function<Integer,Integer> m = (x) -> {return x-10;};
         Integer compose = f.compose(g).apply(3);
         Integer then = f.andThen(g).apply(3);
         System.out.println(compose);
         System.out.println(then);
    }

输出结果是: 7,8
compose方法是先执行before函数,将before函数的结果作为输入再执行。
andThen方法是先执行本函数,将本函数的结果作为after函数的输入再执行
f.compsoe(g) 相当于 f(g(x)), f.andThen(g) 相当于 g(f(x)); 有了这两个方法之后,Function就可以像数学函数一样组合、嵌套使用。
上例中 f.compsoe(g).compose(m).apply(2) 相当于 ((2-10)2)+1= -15。 f.compose(g).andThen(2) 相当于 ((22)+1)-10=-5。

函数式接口: Consumer

Consumer消费者,顾名思义即针对某个东西我们来消费、使用它。因此它包含一个有输入无输出的accept方法。

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

我们可以注意到:Consumer没有compose方法,compose方法需要before函数的结果作为输入,而accet方法没有返回值,也就无法进行compose复合了。

使用示例:

Collection接口继承了另一个迭代器接口Interable, Interable接口中包含一个用于遍历集合的forEach方法,它的参数就是 Consumer接口。

    /**
     *
     * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

函数式接口: Supplier

顾名思义:提供者就是提供一个对象供使用,因此Supplier接口包含一个有输出无输入的get方法。

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

使用示例

jdk提供的对象操作工具类Objects中,有一个requireNonNull方法, 它的作用是判断某对象是否为null, 为null则抛出空指针异常并指定异常信息。异常信息就是通过一个Supplier接口生成的

Objects类
 public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
        if (obj == null)
            throw new NullPointerException(messageSupplier.get());
        return obj;
    }
    
使用举例:
        String param = null;
        Objects.requireNonNull(param, ()->{return "参数不允许为null";});

函数式接口: Predicate

断言型接口:它的作用是进行逻辑判断,因此 Predicate提供了接受一个参数并返回boolean值的test方法。

@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);

   /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ANDed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }


    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ORed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * OR of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }


    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

另外它还提供了逻辑判断的经典”或与非“操作,分别对应or,and, negate方法。

使用示例

在1.8新提供的针对集合的流式操作接口中, Stream包含一个过滤的filter方法,它的参数就是一个Predicate接口,用于判断当前对象是否能通过过滤。

java.util.stream.Stream	类
    /**
     * Returns a stream consisting of the elements of this stream that match
     * the given predicate.
     *
     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
     * operation</a>.
     *
     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
     *                  <a href="package-summary.html#Statelessness">stateless</a>
     *                  predicate to apply to each element to determine if it
     *                  should be included
     * @return the new stream
     */
    Stream<T> filter(Predicate<? super T> predicate);

java.uti.function包扩展介绍之BiFunction,BiConsumer,BiPredicate

上面提到的Function,Consumer, Supplier,Predicate都是jdk1.8 java.uti.function包下面的类。我们打开这个包,就会发现除了这4个外还有许多诸BiFunction,BiConsumer, UnaryOperator这样的类。
在这里插入图片描述

Bi扩展

Bi是Binary(二元) 的缩写,考虑到我们实际生活中存在2个入参的情况(单个入参无法满足,例如比较操作),BiFunction(二元函数)有2个入参,最后也跟Function一样返回一个结果。

@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);
    }
   

同样的, BiConsumer消费2个参数,BiPredicate接收2个参数,返回boolean值。

基本数据类型扩展

另外jdk还贴心的对消费、生产、使用基本数据类型(Int,Long,Double,Boolean)情况做了扩展:DoubleConsumer 只消费double数据, DoubleFunction 的入参是double数字,DoubleToIntFunction接收double,返回int。

public interface DoubleConsumer {

    /**
     * Performs this operation on the given argument.
     *
     * @param value the input argument
     */
    void accept(double value);
    ...
    }

public interface DoubleToIntFunction {

    /**
     * Applies this function to the given argument.
     *
     * @param value the function argument
     * @return the function result
     */
    int applyAsInt(double value);
}

一元扩展

UnaryOperator 是Function的一元形式,接收参数和返回结果是一个类型。

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

    /**
     * Returns a unary operator that always returns its input argument.
     *
     * @param <T> the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}

对应的基础类型扩展有IntUnaryOperator, 接受和返回类型都是int。类似的有 IntUnaryOperator, DoubleUnaryOperator
都是对常用类型的适配

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/152370.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一、Gradle入门

文章目录一、Gradle入门1.1 Gradle 简介1.2 常见的项目构建工具1.3 Gradle 安装1.3.1 Gradle 安装说明1.3.2 安装 JDK1.3.3 下载并解压到指定目录1.3.4 配置环境变量1.3.5 检测是否安装成功1.4 Gradle 项目目录结构1.5 Gradle 创建第一个项目1.5.1 Gradle 中的常用命令1.5.2 修…

【MySQL进阶教程】视图/存储过程/触发器

前言 本文为 【MySQL进阶教程】视图/存储过程/触发器 相关知识&#xff0c;下边将对视图&#xff0c;存储过程&#xff0c;存储函数&#xff0c;触发器等进行详尽介绍~ &#x1f4cc;博主主页&#xff1a;小新要变强 的主页 &#x1f449;Java全栈学习路线可参考&#xff1a;【…

MySQL高级【存储函数触发器】

1&#xff1a;存储函数1.1&#xff1a;介绍存储函数是有返回值的存储过程&#xff0c;存储函数的参数只能是IN类型的。具体语法如下&#xff1a; CREATE FUNCTION 存储函数名称 ([ 参数列表 ]) RETURNS type [characteristic ...] BEGIN -- SQL语句 RETURN ...; END ;character…

如何管理存量用户?

存量市场的老客户对于企业来说如同一座金矿&#xff0c;好好运营老客户&#xff0c;可以给企业带来源源不断的新客户&#xff0c;企业所获得的收益远比拉新所获收益要高的多。 前言 存量客户是指某个时间段里原先已有的客户&#xff0c;与新增客户相对应&#xff0c;通俗点说&…

Python开发Web扫描器实战

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是Python开发Web扫描器实战。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未…

机器学习--模型评估、过拟合和欠拟合、模型验证

目录 一、模型评估 模型指标 常见关于分类的指标 准确率 精确率(精确度) 召回率 F1 score PR曲线&#xff1a; ROC AUC 二、过拟合和欠拟合 训练与泛化误差的区别 什么样的情况会导致欠拟合与过拟合&#xff1f; 模型的复杂度&#xff08;能够拟合各种各样函…

分组加密模式 ECB CBC OFB CFB

多个分组加密互相之间如何关联 ECB模式 每个分组之间单独加密&#xff0c;互不关联 2个分组明文一样&#xff0c;结果也一样&#xff0c;那么只需爆破其中1个就可以了 每个分组互不关联&#xff0c;可以分段同时来爆破&#xff0c;不安全 可以通过替换某段密文来达到替换明…

11.Isaac教程--在docker中模拟训练姿势估计模型

在docker中模拟训练姿势估计模型 文章目录在docker中模拟训练姿势估计模型怎么运行的主机设置硬件要求软件要求NGC Docker 注册表设置第一次运行数据集生成配置您的工作区Jupyter 变量设置开始训练添加您自己的 3D 模型故障排除接下来物体检测和 3D 姿态估计在机器人技术中起着…

『精』EditorConfig 小老鼠 跨编辑器 | IDE 保持一致的编码风格

『精』EditorConfig 小老鼠 跨编辑器 | IDE 保持一致的编码风格 文章目录『精』EditorConfig 小老鼠 跨编辑器 | IDE 保持一致的编码风格一、什么是EditorConfig二、文件识别符三、风格属性控制四、不同规则参考1)、简洁通用2)、前端Vue项目3)、前端React项目4)、前端Angular项…

Linux常用命令——nm命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) nm 显示二进制目标文件的符号表 补充说明 nm命令被用于显示二进制目标文件的符号表。 语法 nm(选项)(参数)选项 -A&#xff1a;每个符号前显示文件名&#xff1b; -D&#xff1a;显示动态符号&#xff1b; …

成员变量-java循环机构

1.概念所谓的成员变量&#xff0c;是指在类中(不是方法或其他代码块)直接定义的变量。根据是否带有static关键字&#xff0c;成员变量又分为静态变量(类变量)、实例变量(对象变量)。成员变量在整个类的内部都有效&#xff0c;可以在当前类的任何方法中使用。另外如果成员变量不…

NFS介绍及服务器搭建

一、NFS 简介 NFS&#xff0c;英文全称 Network File System&#xff0c;主要功能&#xff1a;通过网络&#xff0c;让不同的机器、不同的操作系统可以共享文件。类似windows的共享文件夹 ​ NFS服务器共享本机目录&#xff0c;客户端机器挂载该目录后&#xff0c;就可以像自…

AI+OCR赋能古彝文数字化—让经典重新跳动

1️⃣ 彝文与古彝文概况文化是一个民族社会历史发展到一定程度的产物&#xff0c;代表着文明发展的程度&#xff0c;而文字是文化的一种载体&#xff0c;文字的出现是社会进入文明阶段的重要标志之一&#xff0c;其生动记录着一个民族的智慧成果&#xff0c;深刻反映着一个民族…

Unity 3D 环境特效||Unity 3D 游戏场景设计实例

Unity 3D 环境特效 一般情况下&#xff0c;要在游戏场景中添加雾特效和水特效较为困难&#xff0c;因为需要开发人员懂得着色器语言且能够熟练地使用它进行编程。 Unity 3D 游戏开发引擎为了能够简单地还原真实世界中的场景&#xff0c;其中内置了雾特效并在标准资源包中添加…

mmLab系列使用方法

mmLab系列使用方法环境搭建mmdetection检查数据集运行部署mmdeploy环境搭建使用mmOCRmmsegmentation环境搭建 Windows最推荐安装方法&#xff1a; 首先需要查好自己gpu的CUDA版本&#xff0c;根据版本到pytorch官方网站查找对应的pytorch版本(!!!只查找不下载&#xff01;)ht…

Mybatis源码分析(七)MapperMethod的INSERT分析

目录一 INSERT 语句1.1 参数的对应解析convertArgsToSqlCommandParam1.2 ID获取对应的MappedStatement1.3 MappedStatement交给执行器执行1.4 不同的执行器获取不同的StatementHandler1.5 根据参数获取BoundSql1.6 执行器配置参数处理器ParameterHandler1.7 拿到StatementHandl…

人工智能-http协议和静态服务器

目录1、HTTP协议1.1 网址1.2 http协议的介绍1.3 http请求报文1.&#xff14; http响应报文1.&#xff15;查看http协议的通信过程&#xff12;、静态web服务器程序开发2.1 搭建python自带的静态web服务器2.2 静态web服务器-返回固定页面数据1、HTTP协议 1.1 网址 网站又称为U…

【报错】assert failed: xQueueSemaphoreTake queue.c:1545 (( pxQueue ))

&#x1f331; hi&#xff0c;最近开始写嵌入式&#xff0c;碰到蛮多新的问题&#xff0c;也调bug到凌晨五点过。欢迎关注我&#xff0c;一起讨论交流 开发环境 在VScode中使用Arduino&#xff0c;开发板ESP32S3 报错代码 使用队列接收服务器消息&#xff0c;FIFO依次处理消…

ROS1学习笔记:参数的使用与编程方法(ubuntu20.04)

参考B站古月居ROS入门21讲&#xff1a; 参数的使用与编程方法 基于VMware Ubuntu 20.04 Noetic版本的环境 文章目录一、概念图讲解二、创建功能包三、参数命令行的使用方法&#xff1a;rosparam显示某个参数值&#xff1a;rosparam get设定某个参数值&#xff1a;rosparam set将…

linux小程序—进度条(动态演示)

文章目录1. \n与\r的区别1. linux环境下2. windows环境下2. 缓冲区问题1.\n的情况2.\r的情况3. \n与\r的情况对比4. 使用fflush函数观察\r情况5. 不为\n与\r的情况3.进度条的实现1. printf 打印字符问题1. 修改前2.修改后2 . 注意事项3. 整体实现1. makefile(自动化编译工具&am…