【Stream流基础篇】Java中的函数、函数对象、函数接口和方法引用及转换

什么是函数

在数学中,函数是这样定义的:它是给定一个数集A,假设其中的元素为x,对A中的元素x施加对应法则f,记作f(x),得到另一数集B,假设B中的元素为y,则y与x之间的等量关系可以用y=f(x)表示。

Java中的函数与咱们学的数学中的函数有异曲同工之妙。函数,经常被我们叫做方法,它是执行特定任务或操作的代码块

函数是Java类的一部分,用于执行特定的任务。它们通常有一个返回类型和一个或多个参数

比如我们使用两个整数参数返回它们的和:

public class xiaowei {  
    public int add(int a, int b) {  
        return a + b;  
    }  
}

在这里插入图片描述

函数对象

函数对象是通过Lambda表达式创建的,它表示一个匿名函数。Lambda表达式可以用于实现函数接口,所以可以作为参数传递给其他方法或赋值给变量。

比如我们现在有几种水果组成的列表,把它们的英文名称转化为大写,代码就可以这样写:

List<String> list = Arrays.asList("Apple", "Banana", "Cherry");  
list.forEach(s -> System.out.println(s.toUpperCase()));

s -> System.out.println(s.toUpperCase())就是一个Lambda表达式,它表示一个匿名函数,接受一个字符串参数s,然后将它转换为大写后打印出来。这个Lambda表达式实现了Consumer函数接口。接下来我们讲一下什么是函数接口!

函数接口

函数接口是只有一个抽象方法的接口。Java 8版本中引入的许多内置函数接口(这个见下面详细的表格)。Lambda表达式可以被用来实现这些接口,所以才允许我们将函数作为参数传递。

常见的Java 8内置函数接口及其用途:

接口名称描述示例
Function<T, R>将一个输入参数T转换为结果RFunction<Integer, String> toStringFunction = i -> String.valueOf(i);
Predicate<T>对输入参数T进行断言,返回结果是布尔值Predicate<String> isEmptyPredicate = s -> s.isEmpty();
Consumer<T>消费输入参数T,不返回结果(void)Consumer<String> printConsumer = s -> System.out.println(s);
Supplier<T>无需输入参数,提供(生成)一个结果T,和上面那行相反Supplier<String> defaultSupplier = () -> "Default";
UnaryOperator<T>对一个输入参数T进行一元操作,返回同类型结果UnaryOperator<Integer> incrementOperator = i -> i + 1;
BinaryOperator<T>对两个同类型输入参数T进行二元操作,返回同类型结果BinaryOperator<Integer> additionOperator = (a, b) -> a + b;
BiFunction<T, U, R>接受两个输入参数TU,返回一个结果RBiFunction<Integer, Integer, Integer> multiplicationFunction = (a, b) -> a * b;

这些函数接口都只有一个抽象方法,与Lambda表达式结合使用,可以实现各种功能。

比如,我们可以使用Function接口将一个列表中的每个元素转换为另一种形式,使用Predicate接口过滤列表中的元素,使用Consumer接口对列表中的每个元素执行某种操作,等等。

举个栗子:

我们创建一个包含整数的列表。然后,我们使用Function,Predicate,Consumer接口等接口来演示如何使用它们。代码来咯:

import java.util.Arrays;  
import java.util.List;  
import java.util.function.Consumer;  
import java.util.function.Function;  
import java.util.function.Predicate;  
  
public class XiaoWeiDemo1 {  
  
    public static void main(String[] args) {  
        // 创建一个整数列表  
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
        
        // 使用Function接口将整数转换为字符串  
        Function<Integer, String> toStringFunction = number -> String.valueOf(number);  
        List<String> numberStrings = numbers.stream()  
                                               .map(toStringFunction)  
                                               .collect(Collectors.toList());  
        System.out.println("Number strings: " + numberStrings);  
  
        // 使用Predicate接口过滤出偶数  
        Predicate<Integer> isEvenPredicate = number -> number % 2 == 0;  
        List<Integer> evenNumbers = numbers.stream()  
                                              .filter(isEvenPredicate)  
                                              .collect(Collectors.toList());  
        System.out.println("Even numbers: " + evenNumbers);  
  
        // 使用Consumer接口打印每个偶数  
        Consumer<Integer> printConsumer = number -> System.out.println("Even number: " + number);  
        evenNumbers.forEach(printConsumer);  
    }  
}

这就是Java 8函数接口的强大之处,它们可以让代码更加模块化、可重用和易于测试。我们只需要灵活地传递代码块作为参数,就可以需要的地方执行它们。

我们这个栗子里面用到了Stream流的几个API,比如过滤(filter),收集(collect)这些,这些API会在后续的文章里再和大家一起详细学习。

方法引用

方法引用也是Java 8中引入的一个特性,它允许我们直接引用已经存在的方法,而不是在Lambda表达式中重新编写方法体。方法引用主要有四种类型,每种类型都有其特定的使用方式:

  1. 静态方法引用:当引用的方法是静态方法时,我们可以使用类名来进行引用。例如,对于Math类中的max方法,我们可以使用Math::max来进行引用。这种方式适用于不需要访问对象的实例成员的情况。

  2. 实例方法引用:当引用的方法是实例方法时,我们可以使用对象名来进行引用。例如,假设我们有一个String对象str,并且想要引用它的length方法,那么可以使用str::length。这种方式允许我们直接引用特定对象的实例方法。

  3. 构造方法引用:当引用的方法是构造方法时,我们可以使用类名来引用。例如,要引用ArrayList类的构造方法,我们可以使用ArrayList::new。这种方式在需要创建对象实例时特别有用,尤其是在结合Stream API进行集合操作时。

  4. 数组构造方法引用:当引用的方法是数组构造方法时,我们可以使用数组类型来引用。例如,要引用int数组的构造方法,我们可以使用int[]::new。这种方式在需要动态创建数组时非常有用。

计算两个数之和案例

我们定义一个函数接口来计算两个数的和,然后使用Lambda表达式、方法引用等方式来实现它。

首先,我们定义一个函数接口BinaryOperator,它接受两个参数并返回一个结果。(见上文表格详情)这个接口类似于Java 8中的java.util.function.BinaryOperator接口,但为了演示如何使用,我们重新实现一个:

@FunctionalInterface  
public interface BinaryOperator<T> {  
    T apply(T a, T b);  
}

这里需要注意一下@FunctionalInterface注解:

@FunctionalInterface 是 Java 8 引入的一个注解,用来指示一个接口是函数式接口。函数式接口是指只包含一个抽象方法的接口(但是可以包含多个默认方法或者静态方法,但但是只能有一个抽象方法)。

接下来,我们创建一个类Calculator,它包含使用BinaryOperator接口的方法:

public class Calculator {  
      
    // 使用函数接口作为参数的方法  
    public static <T> T calculate(T a, T b, BinaryOperator<T> operator) {  
        return operator.apply(a, b);  
    }  
      
    // 一个静态方法,用于计算两个数的和,可以作为方法引用  
    public static int add(int a, int b) {  
        return a + b;  
    }  
      
    public static void main(String[] args) {  
        // 使用Lambda表达式实现函数接口  
        BinaryOperator<Integer> sumLambda = (a, b) -> a + b;  
        int sumUsingLambda = calculate(5, 3, sumLambda);  
        System.out.println("Sum using Lambda: " + sumUsingLambda);  
          
        // 使用方法引用实现函数接口  
        BinaryOperator<Integer> sumMethodRef = Calculator::add;  
        int sumUsingMethodRef = calculate(5, 3, sumMethodRef);  
        System.out.println("Sum using Method Reference: " + sumUsingMethodRef);  
          
        // 直接使用函数对象(在这种情况下是静态方法)  
        int sumUsingStaticMethod = Calculator.add(5, 3);  
        System.out.println("Sum using Static Method: " + sumUsingStaticMethod);  
    }  
}

在main方法中,我们使用三种函数接口的方式:

第一种:使用Lambda表达式:我们创建了一个Lambda表达式(a, b) -> a + b,它实现了BinaryOperator接口,所有我们可以直接作为参数传递给calculate方法。

第二种:使用方法引用:我们通过Calculator::add引用了Calculator类中的静态方法add,这个方法同样实现了BinaryOperator接口的功能。方法引用是Lambda表达式的一种简写形式,当Lambda表达式的体只是调用一个已存在的方法时,可以使用方法引用。

第三种:直接使用函数对象:在这种情况下,我们直接调用了静态方法Calculator.add(5, 3),这不是通过函数接口调用的,但它展示了如何直接调用实现特定功能的函数对象(在这个例子中是静态方法)。

运行这段代码,会输出:

Sum using Lambda: 8
Sum using Method Reference: 8
Sum using Static Method: 8

方法引用与Lambda表达式转换

虽然Lambda表达式和方法引用在语法上有所不同,但在某些情况下,它们可以相互转换。这主要取决于函数式接口的抽象方法的签名和你想要引用的方法的签名是否匹配

从Lambda表达式到方法引用:如果我们的Lambda表达式仅仅是调用了一个已存在的方法,并且这个方法的签名与函数式接口的抽象方法的签名完全匹配,那么就可以将这个Lambda表达式转换为一个方法引用。

例如,下面Lambda表达式:

Function<String, String> toUpperCaseLambda = s -> s.toUpperCase();

可以转换为下面的方法引用:

Function<String, String> toUpperCaseMethodRef = String::toUpperCase;

从方法引用到Lambda表达式:反过来,如果我们已经有一个方法引用,并且想要更明确地表达正在做什么,或者需要添加一些额外的逻辑,我们就可以将它转换为一个Lambda表达式。

比如,方法引用为:

Function<String, String> toUpperCaseMethodRef = String::toUpperCase;

可以转换为下面的Lambda表达式:

Function<String, String> toUpperCaseLambda = s -> {  
    String upperCaseString = s.toUpperCase();  
    // 我们可以在这里添加额外的逻辑,如日志记录、错误处理等。  
    return upperCaseString;  
};

文章到这里就先结束了,后续会继续分享相关的知识点。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytorch中的过拟合和欠拟合

基本概念 我们知道&#xff0c;所谓的神经网络其实就是一个复杂的非线性函数&#xff0c;网络越深&#xff0c;这个函数就越复杂&#xff0c;相应的表达能力也就越强&#xff0c;神经网络的训练则是一个拟合的过程。   当模型的复杂度小于真实数据的复杂度&#xff0c;模型表…

GMSSL编译iOS

一、GMSSL-2.x 国密SDK源码下载&#xff0c;对GMSSL库进行编译生成对应的静态库。执行如下命令&#xff1a; cd到SDK源码目录 cd /Users/xxxx/Downloads/GMSSLV2-master查看SDK适用环境 ./config上图中错误解决方法 使用文本编辑器打开SDK目录下Configure、test/build.info、…

【STM32F407+CUBEMX+FreeRTOS+lwIP之UDP记录】

STM32F407CUBEMXFreeRTOSlwIP之UDP记录 基本信息cubemx配置GPIONVICRCCSYSETHFREERTOSlwIP UDP&#xff08;SOCKET&#xff09;效果 UDP广播&#xff08;SOCKET&#xff09;效果 UDP组播&#xff08;SOCKET&#xff09;cubemx注意以下ethernetif.c效果 可参考正点原子和野火的手…

深度学习论文:Local Feature Matching Using Deep Learning: A Survey

深度学习论文: Local Feature Matching Using Deep Learning: A Survey Local Feature Matching Using Deep Learning: A Survey PDF: https://arxiv.org/pdf/2401.17592 1 概述 近年来&#xff0c;深度学习模型的引入引发了对局部特征匹配技术的广泛探索。本文旨在全面概述局…

go语言实现简单ngnix样例

目录 1、代码实现样例&#xff1a; 2、postman调用ngnix&#xff0c;转发&#xff1a; 1、代码实现样例&#xff1a; package mainimport ("bytes""encoding/json""io""log""net/http""net/http/httputil""…

防止核心研发数据流失:管理者跳槽怎么办?

在高速发展的科技行业中&#xff0c;核心研发数据是企业最宝贵的资产之一。然而&#xff0c;当高层管理人员或核心技术人员因跳槽等原因离开公司时&#xff0c;他们可能会无意中或有意地携带走企业的核心研发数据&#xff0c;这对于任何企业来说都是一个巨大的风险。为了有效地…

Vue---组件

Vue—组件 目录 Vue---组件定义组件全局组件局部组件 组件通讯***重点***父子通信之父传子&#xff08;props&#xff09;父子通信之子传父&#xff08;$emit&#xff09;ref属性&#xff08;$refs&#xff09; 动态组件插槽命名插槽 定义组件 全局组件 vue2中template只能传…

ArcGIS小技巧—基于点数据的密度分析(含练习数据)

关于空间点数据的密度分析&#xff0c;Arcgis Map中提供了基础的点密度分析和核密度分析。核密度分析可以通过手动设置搜索半径&#xff0c;调整密度分布的合理性。 但有时由于实际工作的需要&#xff0c;我们需要对研究范围做特定划分&#xff0c;比如根据格网规则划分做密度…

Flask框架进阶-Flask流式输出和受访配置--纯净详解版

Flask流式输出&#x1f680; 在工作的项目当中遇到了一种情况&#xff0c;当前端页面需要对某个展示信息进行批量更新&#xff0c;如果直接将全部的数据算完之后&#xff0c;再返回更新&#xff0c;则会导致&#xff0c;前端点击刷新之后等待时间过长&#xff0c;开始考虑到用进…

电脑录制视频快捷键,一键开启录屏新时代(干货)

“最近尝试录制一些电脑上的操作视频&#xff0c;用来制作教学教程。不过&#xff0c;每次录制都要通过菜单或搜索来打开录屏软件&#xff0c;实在是有些繁琐。有没有人知道哪些电脑录制视频的快捷键呀&#xff1f;或者有没有通用的快捷键设置方法&#xff1f;” 在当今数字时…

CMake+qt+Visual Studio

#使用qt Creator 创建Cmake 项目,使用Cmake Gui 生成sln 工程&#xff0c;使用Visual Studio 开发 ##使用qt Creator 创建CMake项目 和创建pro工程的步骤一致&#xff0c;只是在选择构建系统的步骤上选择CMake,接下来步骤完全相同 工程新建完成之后&#xff0c;构建cmake 项…

PE文件(三)节表作业

本次作业以notepad进行演示&#xff0c;如下是其在硬盘上的内存 1.手动解析节表 由标准pe头可知&#xff0c;一共由7个节也就是7个节表&#xff0c;可选pe头的大小是0X00F0&#xff0c;即240字节大小 根据上述我们所获取的信息&#xff0c;找到节表的首地址为0x01F8 .text …

微服务:Nacos注册中心

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Nacos注册中心 一、服务注册与发现1.启动Nacos…

Vite proxy-rewrite 属性详解

在前端开发中&#xff0c;为了避免跨域问题&#xff0c;我们会在vite.config.ts 中配置如下问题 rewrite: 由于不了解Nginx的知识&#xff0c;这个属性一直困扰着我&#xff0c;这个重写有啥用&#xff0c;加和不加有啥影响 server: {host: 0.0.0.0,proxy: {/api: {target: ht…

手机通讯录删除了怎么恢复?这里几个方法超快找回!

当我们不小心删除了手机通讯录中的联系人&#xff0c;或者手机丢失导致通讯录信息丢失&#xff0c;恢复通讯录就变得非常重要了。手机通讯录删除了怎么恢复&#xff1f;我们该如何快速找回这些重要的联系人信息呢&#xff1f;下面我们将介绍2种简单易行的方法&#xff0c;帮助您…

Spark核心名词解释与编程

Spark核心概念 名词解释 1)ClusterManager&#xff1a;在Standalone(上述安装的模式&#xff0c;也就是依托于spark集群本身)模式中即为Master&#xff08;主节点&#xff09;&#xff0c;控制整个集群&#xff0c;监控Worker。在YARN模式中为资源管理器ResourceManager(国内…

树莓集团整合行业资源 优化数字产业生态圈

树莓集团&#xff0c;作为国际数字影像产业园的运营方以及链主企业&#xff0c;自创立以来&#xff0c;一直致力于整合行业优质资源&#xff0c;为数字科技领域的优秀企业提供一片肥沃的创新土壤。随着信息技术的迅猛发展和数字经济的深入推进&#xff0c;树莓集团深知自身的责…

七彩虹(Colorful)隐星P16 2023款笔记本电脑原装出厂Win11系统镜像下载 带建Recovery一键还原功能

七彩虹原厂Windows预装OEM专用系统&#xff0c;恢复出厂开箱状态一模一样 适用型号&#xff1a;隐星P16 23 链接&#xff1a;https://pan.baidu.com/s/1Ig5MQMiC8k4VSuCOZRQHUw?pwdak5l 提取码&#xff1a;ak5l 原厂W11系统自带所有驱动、出厂时自带的主题与专用壁纸、系…

机器学习在医疗行业的应用:颠覆传统诊疗模式,开启智慧医疗新时代

文章目录 一、精准诊断的突破二、药物研发的革新三、患者管理的智能化四、智能辅助决策系统五、机器学习在医疗行业的前景 随着科技的飞速发展&#xff0c;机器学习作为人工智能的核心技术&#xff0c;正逐渐渗透到各个行业中&#xff0c;其中在医疗行业的应用尤为引人瞩目。机…