深入了解Java 8 新特性:lambda表达式进阶

news2024/10/5 13:07:04

阅读建议

嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议:

  1. 本篇文章大概7000多字,预计阅读时间长需要10分钟。
  2. 本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章,建议收藏起来,方便时常学习与回顾,温故而知新。
  3. 创作不易,免费的点赞、关注,请走上一走,算是对博主一些鼓励,让我更有动力输出更多的干货内容。

前言

        Java 8中的Lambda表达式是一种匿名函数,它允许你将函数作为方法参数进行传递,或者把代码更简洁地定义在你的应用程序里。另外Java的函数式编程就是Lambda表达式,java的函数式接口的有一个明显特征:有且仅有一个抽象方法的接口。下面是一些常见的Java内置的函数式接口梳理,掌握这些内置的函数式接口是相当有必要的,因为作为一种更简洁、更灵活和更易于维护的编程方式,这在很多的java相关的框架技术中有大量的应用,相信有喜欢钻研源码小伙伴应该深有体会。

Java内置的函数式接口

Function<T,R>

        Function接口是Java 8中引入的一个函数式接口,它位于java.util.function包中。这个接口表示一个输入参数能够产生一个结果的函数。Function接口只有一个抽象方法,即apply(T t),它接受一个参数并返回一个结果。

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

        下面是一个使用Function接口的简单示例:

@Test
public void test5() {
    Function<String, Student> function = str -> new Student(str);
    Student student = function.apply("张三");
    log.info(student.getName());
}

        在Java中,Function接口的默认实现包括以下几种:

  • Function.andThen(Function after):这个方法返回一个新函数,它首先应用原始函数,然后应用另一个函数。也就是说,这个新函数首先将输入映射到某个结果,然后将结果映射到另一个结果。假设我们有一个Function,它接受一个整数作为输入,并返回一个整数作为输出。现在,我们想在这个函数的基础上添加一个新的函数,将得到的整数加倍。
@Test
public void test7() {
    Function<Integer, Integer> originalFunction = x -> x * 2;
    Function<Integer, Integer> newFunction = x -> x * 2;
    Function<Integer, Integer> composedFunction = originalFunction.andThen(newFunction);
    int input = 5;
    int result = composedFunction.apply(input);
    System.out.println(result);  // 输出:20
}

在上面的示例中,我们定义了一个原始函数originalFunction,它接受一个整数作为输入,并将其乘以2。然后,我们定义了一个新的函数newFunction,它也接受一个整数作为输入,并将其乘以2。接下来,我们使用andThen方法将这两个函数组合成一个新的函数composedFunction。最后,我们将输入整数5传递给composedFunction,并打印结果。在这个例子中,首先将输入整数5乘以2得到10,然后将10乘以2得到20,最终输出结果为20。

  • Function. compose(Function before):这个方法返回一个新函数,它首先应用另一个函数,然后将结果映射到原始函数的输入。也就是说,这个新函数首先将输入映射到另一个输入,然后将这个输入映射到结果。假设我们有两个函数,一个将字符串转换为大写,另一个将字符串长度截断为5个字符。这两个函数可以组合成一个新函数,首先将字符串转换为大写,然后将其长度截断为5个字符。
@Test
public void test6(){
    Function<String, String> toUpperCase = str -> str.toUpperCase();
    Function<String, String> truncate = str -> str.substring(0, 6);
    Function<String, String> composedFunction = toUpperCase.compose(truncate);
    String input = "hello world!";
    String result = composedFunction.apply(input);
    System.out.println(result);  // 输出:"HEL"
}

在上面的示例中,我们首先定义了两个函数:toUpperCase和truncate。然后,我们使用compose方法将它们组合成一个新函数composedFunction。最后,我们调用composedFunction对输入字符串进行操作,并打印结果。

BiFunction

        BiFunction接口是Java 8中引入的一个函数式接口,它位于java.util.function包中。BiFunction接口表示一个接受两个输入参数并返回一个结果的函数。它与Function接口类似,但多了一个输入参数。

        BiFunction接口的定义如下:

@FunctionalInterface
public interface BiFunction<T, U, R> {

    R apply(T t, U u);
  
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

        其中,T和U是输入参数的类型,R是返回结果的类型。apply()方法是抽象的,需要具体的实现来提供具体的逻辑。

        下面是一个使用BiFunction接口的示例:

@Test
public void test8() {
    BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
    int result = add.apply(2, 3);
    System.out.println(result);  // 输出:5
}

在上面的示例中,我们定义了一个add函数,它接受两个整数作为输入,并将它们相加得到一个整数作为结果。我们使用apply()方法调用该函数并传递两个参数2和3,然后打印结果5。

        BiFunction接口包含一个默认实现,即andThen方法,用于将两个函数组合在一起。它接受一个BiFunction作为参数,并返回一个新的函数,该函数将先应用原始函数,然后应用给定的函数。

@Test
public void test9() {
    BiFunction<Integer, Integer, String> addAndToString = (x, y) -> Integer.toString(x + y);
    Function<String, String> toUpperCase = str -> str.toUpperCase();
    BiFunction<Integer, Integer, String> composedFunction = addAndToString.andThen(toUpperCase);
    int input1 = 2;
    int input2 = 3;
    String result = composedFunction.apply(input1, input2);
    System.out.println(result);  // 输出:"5"  
}

在上面的示例中,我们定义了一个addAndToString函数,它接受两个整数作为输入,并将它们的和转换为字符串。然后,我们定义了一个toUpperCase函数,它接受一个字符串作为输入,并将其转换为大写。接下来,我们使用andThen方法将两个函数组合成一个新的函数composedFunction。最后,我们调用composedFunction对输入整数2和3进行操作,并打印结果"5"。首先将输入整数2和3相加得到5,然后将5转换为字符串"5",最后将字符串"5"转换为大写"5",最终输出结果为"5"。

Predicate

        Predicate 是 Java 中的一个函数式接口,它位于 java.util.function 包中。这个接口用于表示一个参数的谓词(即,条件判断),接收一个参数并返回一个布尔值,通常用于判断参数是否满足指定的条件

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);

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

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

    @SuppressWarnings("unchecked")
    static <T> Predicate<T> not(Predicate<? super T> target) {
        Objects.requireNonNull(target);
        return (Predicate<T>)target.negate();
    }
}

        Predicate接口的主要方法是 test(),它接收一个参数并返回一个布尔值。下面是一个简单的例子:

@Test
public void test3(){
    Student student = new Student("张三");
    Predicate<Student> predicate= obj -> "张三".equals(obj.getName());
    boolean flag = predicate.test(student);
    Assert.isTrue(flag,"test fail");
    boolean flag2 = predicate.test(new Student("李四"));
    Assert.isTrue(flag2,"test fail");
}

Predicate:常用的四个方法:

  • boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值。
  • default Predicate negate():返回一个逻辑的否定,对应逻辑非。
  • default Predicate and(Predicate other):返回一个组合判断,对应短路与。
  • default Predicate or(Predicate other):返回一个组合判断,对应短路或。
@Test
public void test4(){
    Student student = new Student("张三");
    Predicate<Student> predicate= obj -> "张三".equals(obj.getName());
    Predicate<Student> predicate2= obj-> "李四".equals(obj.getName());
    Predicate<Student> or = predicate2.or(predicate);
    boolean flag = or.test(student);
    Assert.isTrue(flag,"test fail");
    student.setName("李四");
    boolean flag2 = or.test(student);
    Assert.isTrue(flag2,"test fail");
    Predicate<Student> predicate3=obj->18==obj.getAge();
    student.setAge(18);
    Predicate<Student> and = predicate3.and(predicate2);
    boolean flag3 = and.test(student);
    Assert.isTrue(flag3,"test fail");
    student.setName("铁蛋");
    boolean test = and.test(student);
    Assert.isTrue(test,"学生姓名不等于张三或者李四");
}

Consumer

        Consumer接口代表了一个接受输入参数并返回void的函数。它的主要作用是消费输入数据,也就是说,对输入进行某种操作,但不返回任何结果。

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
    
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

        Consumer接口的主要方法是void accept(T t):对给定的参数执行此操作。

@Test
public void test2() {
    Student student = new Student("zhangsan");
    Consumer<String> nameConsumer = str -> student.setName(str);
    nameConsumer.accept("lisi");//设置学生的姓名为拼音-小写
    log.info(student.getName());
    Assert.isTrue("lisi".equals(student.getName()), "test fail!");  
}

        Consumer接口的默认实现,andThen方法,用于将两个Consumer合并在一起。它允许你将一个操作(即第二个Consumer)附加到另一个操作(即第一个Consumer)的后面,以便在原始操作完成之后执行附加操作。

        下面是一个简单的示例,演示如何使用andThen方法:

@Test
public void test2() {
    Student student = new Student("zhangsan");
    Consumer<String> nameConsumer = str -> student.setName(str);
    Consumer<String> nameConsumer2 = name -> student.setName(name.toUpperCase());
    Consumer<String> nameConsumer3 = nameConsumer.andThen(nameConsumer2);//设置学生的姓名为拼音-大写
    nameConsumer3.accept("lisi");
    log.info(student.getName());
    Assert.isTrue("LISI".equals(student.getName()), "test fail!");
}

Supplier

        这个接口表示一个不接受任何参数但返回结果的函数

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

        特点:

  • 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据。
  • Supplier接口也称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。

        使用示例:        

private String getStuName(Supplier<Student> supplier) {
    String name = supplier.get().getName();
    return name;
}

@Test
public void test() {
    String name = this.getStuName(() -> new Student("zhangsan"));
    log.info(name);
    Assert.isTrue(name.equals("zhangsan"), "test fail");
}

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

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

相关文章

这个双11,阿里云经历了可能是历史级的大故障!

2023年11月12日17&#xff1a;44开始&#xff0c;阿里云发生严重故障&#xff0c;导致阿里巴巴大量产品无法连接&#xff0c;一时间&#xff0c;“阿里云盘崩了”、“淘宝又崩了”、“闲鱼崩了”、“钉钉崩了”等话题相继登上热搜。 此外&#xff0c;像纳思云充电桩、乐爽coole…

Git安装与常用命令

Git简介&#xff1a; Git是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或大或小的项目。Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。Git与常用的版本控制工具CVS、Subversion等不同&#xff0c;它采用了分布式…

机器学习算法——集成学习

目录 1. Bagging 1. Bagging Bagging&#xff08;bootstrap aggregating&#xff1a;自举汇聚法&#xff09;也叫装袋法&#xff0c;其思想是通过将许多相互独立的学习器的结果进行结合&#xff0c;从而提高整体学习器的泛化能力&#xff0c;是一种并行集成学习方法。 工作流…

IO流-框架

一&#xff0c;框架概念 二&#xff0c;Commons-io框架 三&#xff0c;使用案例 package BigDecimal;import org.apache.commons.io.FileUtils;import java.io.File; import java.io.IOException;public class Main12 {public static void main(String[] args) throws IOExcept…

centos7安装mongodb

1、下载mongodb https://www.mongodb.com/try/download/community 2、解压 3、重命名 4、创建mongodb的data、logs目录 5、启动mongodb, bin/mongod --port27017 --dbpath/data/program/mongodb/data --logpath/data/program/mongodb/logs/mongodb.log --bind_ip0.0.0.0 --f…

VMware Workstation Pro 12 ubuntu 20.04 突然奔溃,重新打开后导致win11系统蓝屏问题

1、虚拟机在执行一个程序时候&#xff0c;突然导致系统win11蓝屏 2、重新打开提示磁盘打开异常&#xff0c;网络搜索发现要删除磁盘lock文件&#xff0c;删除后&#xff0c;重启过程中还是会报各种异常 后来把所有的临时文件都删除了&#xff0c;就可以了 临时文件&#xff1…

【Proteus仿真】【51单片机】防火防盗GSM智能家居设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使用声光报警模块、LCD1602显示模块、DS18B20温度、烟雾传感器模块、按键模块、PCF8591 ADC模块、红外检测模块等。 主要功能&#xff1a; 系统运行后…

合伙人如何承担合伙公司债务

合伙企业有不同的组织方式&#xff0c;包括普通合伙企业、特殊的普通合伙企业、有限合伙企业这三种&#xff0c;合伙人对于合伙企业的债务承担方式有以下几种情形&#xff1a; 1.普通合伙人合伙企业债务的承担 普通合伙企业由普通合伙人组成&#xff0c;合伙人对合伙企业债务承…

kernel32.dll下载地址分享,Kernel32.DLL文件丢失的修复指南

作为计算机用户&#xff0c;我们可能都曾遭遇过这样一条令人烦恼的错误信息&#xff1a; "程序无法启动&#xff0c;因为您的计算机中缺少Kernel32.dll"。在这种情况下&#xff0c;往往会引发一系列疑问&#xff1a; Kernel32.dll是什么&#xff1f;为什么它对我的电…

Java学习之路 —— Java高级

文章目录 前言1. 单元测试2. 反射2.1 获取Class对象的三种方式2.2 获取类的构造器的方法2.3 获取类的成员变量2.4 获取类的成员方法2.5 反射的作用 3. 注解3.1 自定义注解3.2 注解的原理3.3 元注解3.4 注解的解析 4. 动态代理5. 总结 前言 终于走到新手村的末端了&#xff0c;…

竞赛 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

Leetcode—142.环形链表II【中等】

2023每日刷题&#xff08;三十三&#xff09; Leetcode—142.环形链表II 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* …

腾讯云服务器怎么样好用吗?腾讯云服务器性能评测

近年来&#xff0c;腾讯云作为一家领先的云服务提供商&#xff0c;备受关注。尤其是最近两年&#xff0c;腾讯云在优惠活动上的力度非常大&#xff0c;被誉为良心云。其优惠政策吸引了越来越多的用户选择腾讯云作为他们的云服务提供商。 腾讯云双十一领9999代金券 https://111…

微信小程序动态生成表单来啦!你再也不需要手写表单了!

dc-vant-form 由于我们在小程序上涉及到数据采集业务&#xff0c;需要经常使用表单&#xff0c;微信小程序的表单使用起来非常麻烦&#xff0c;数据和表单是分离的&#xff0c;每个输入框都需要做数据处理才能实现响应式数据&#xff0c;所以我开发了dc-vant-form&#xff0c;…

shopee选品工具:Shopee选品工具—知虾精准选品与科学运营的利器

在如今竞争激烈的电商市场中&#xff0c;如何进行精准选品和科学运营成为了每个卖家都需要面对的问题。而Shopee选品工具——知虾&#xff0c;作为一款强大的大数据采集及分析平台&#xff0c;为卖家提供了全面的市场分析、产品分析和店铺分析功能&#xff0c;帮助卖家发现市场…

IPv4数据报格式

IPv4是IP协议的第四个版本(版本1-3和版本5都未曾使用过)IP地址不能反映任何有关主机位置的地理信息以前还有个逆地址解析协议RAPR(Reverse APR)&#xff0c;它的作用是使只知道自己MAC地址的主机能通过RAPR找到其IP地址&#xff0c;而现在的DHCP(Dynamic Host Configuration Pr…

Leetcode—876.链表的中间结点【简单】

2023每日刷题&#xff08;三十三&#xff09; Leetcode—876.链表的中间结点 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* middleNode(struct ListNode* head) {struct ListNod…

vue-组件通信(二)

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue-组件通信(二) 目录 组件通信(二) &#xff08;1&#xff09; props / $emit 1. 父组件向子组…

动手学深度学习——循环神经网络(原理解释与代码详解)

文章目录 一、循环神经网络1. 无隐状态的神经网络2. 有隐状态的循环神经网络3. 基于循环神经网络的字符级语言模型4. 困惑度5. 小结 二、循环神经网络的从零开始实现1. 独热编码2. 初始化模型参数3. 循环神经网络模型4. 预测5. 梯度裁剪6. 训练 一、循环神经网络 n元语法模型&…