Java 函数式编程

Java8 函数式编程 Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来对 Java 集合运算和表达的高阶抽象。Stream API 可以极大提高 Java 程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 变换,聚合等。 阅读详情

声明式编程(Declarative Programming)是一种编程风格,我们说明想要完成什么(what),而不是指明怎么做(how)。 --《On Java》
与之相对的是命令式编程(Imperative Programming),后者关注具体的步骤和操作顺序。声明式编程通常更简洁、更易于理解和维护。

Java 8 引入了新特性:
● 函数式编程:包括Lambda 表达式、函数式接口、方法引用等
● 接口默认方法和静态方法:增强接口的功能,支持函数式编程。
Stream API、Optional 提高了代码的简洁性和可读性,开发中用的比较多。
但是 Javaer 常常忽略了函数式编程带来的影响或者它的作用,也就是代码风格的改变。这里抛砖引玉,不讲原理,直讲开发的中的改变。

Java 8 提供了一些常用的内置函数式接口:
● Function<T, R>:接受一个参数,返回一个结果。
● Predicate:接受一个参数,返回一个布尔值。
● Supplier:不接受参数,返回一个结果。
● Consumer:接受一个参数,不返回结果。

一、命令式编程

在web编程里,良好的编程习惯式不能把底层的实体类(DO)直接返回给请求接口,常常涉及到一些类型转换。
JDK 8 之前类型转换一般有几种做法:
● 类型直接写在业务代码里
● 把类型转换代码放到 private 方法里
● 把类型转换代码放到一个类型转换类中
这样做的缺点:
● 可读性差:代码冗长,不适合给代码审核人员/其他开发快速了解业务逻辑

 public void saveTask(WarningTaskAddCriteria req) {
    // 存储预警任务基本信息
    SysWarningTaskEntity taskEntity = new SysWarningTaskEntity()
            .setWarningEventId(req.getTaskEventInfo().getWarningEventId())
            .setWarningEventName(req.getTaskEventInfo().getWarningEventName())
            .setTaskStatus(TaskStatus.SAVED.getCode())
            .setAddAttributes();
    BeanUtils.copyProperties(req,taskEntity);
    final int taskInsertAffectedRows = taskMapper.insert(taskEntity);
    // 省略其他操作
}

二、声明式(函数式)编程

函数式接口可以作为参数、返回结果,也可以组合使用。
举个简单的例子 类型转化类 。个人习惯是封装一层,团队统一代码风格。

类型转化类:

import java.util.function.Function;

public class TypeConverter {
    public static <T, R> R convert(T t, Function<T, R> function) {
        if (t == null || function == null) {
            throw new IllegalArgumentException("Arguments cannot be null");
        }
        return function.apply(t);
    }
}

改造后的代码:

public void saveTask(WarningTaskAddCriteria req) {
        // 存储预警任务基本信息
        SysWarningTaskEntity taskEntity = TypeConverter.convert(req.getTaskEventInfo(), info -> {
            SysWarningTaskEntity entity = new SysWarningTaskEntity()
                    .setWarningEventId(info.getWarningEventId())
                    .setWarningEventName(info.getWarningEventName())
                    .setTaskStatus(TaskStatus.SAVED.getCode())
                    .setAddAttributes();
            SpringBeanUtils.copyProperties(req, entity);
            return entity;
        });

        final int taskInsertAffectedRows = taskMapper.insert(taskEntity);
        // 省略其他操作
}

// 更极端一些
public void saveTask(WarningTaskAddCriteria req) {
    // 存储预警任务基本信息
    final int taskInsertAffectedRows = taskMapper.insert(TypeConverter.convert(req.getTaskEventInfo(), info -> {
        SysWarningTaskEntity entity = new SysWarningTaskEntity()
                .setWarningEventId(info.getWarningEventId())
                .setWarningEventName(info.getWarningEventName())
                .setTaskStatus(TaskStatus.SAVED.getCode())
                .setAddAttributes();
        SpringBeanUtils.copyProperties(req, entity);
        return entity;
    }));
    // 省略其他操作
}

改造后的优点:
● 可读性更强:虽然代码看起来只是放到不同的地方,但是 其他开发人员看到 TypeConverter.convert就会明白这个是要做什么(what) 而不是 怎么做(how)。
● 更易于维护:在实际工作中见到过太多情况,前面声明一个类,然后后面的代码又对这个对象进行更改。一般来讲 final 的对象更加安全可靠。

三、风格改变会有什么影响吗?

3.1 事务是否会有影响?

答案是不会有影响。

@Transactional
public void saveTask(WarningTaskAddCriteria req) {
    SysWarningTaskEntity taskEntity = new SysWarningTaskEntity()
        .setWarningEventId(req.getTaskEventInfo().getWarningEventId())
        .setWarningEventName(req.getTaskEventInfo().getWarningEventName())
        .setTaskStatus(TaskStatus.SAVED.getCode())
        .setAddAttributes();
    BeanUtils.copyProperties(req, taskEntity);

    // 这里仅仅是为了演示,没必要这么写
    Consumer<SysWarningTaskEntity> save = entity -> {
        taskMapper.insert(entity);
    };
    save.accept(taskEntity);

    // 强制抛出异常测试回滚
    throw new RuntimeException("Test rollback");
}

四、函数式例子

4.1 链式函数调用

public JobDetails findJobById(String jobId) {
    // 查询任务基础信息
    Function<String,JobDetails> queryJobBaseInfo = id -> {
        JobDetails jobDetails = new JobDetails();
        final SysWarningJobEntity jobBaseInfo = jobMapper.selectById(id);
        jobDetails.setJobGroupId(jobBaseInfo.getJobGroup());
        BeanUtils.copyProperties(jobBaseInfo,jobDetails);
        return jobDetails;
    };

    // 查询任务参数信息
    Function<JobDetails, JobDetails> queryJobParams = jobDetails -> {
        LambdaQueryWrapper<SysWarningJobParamEntity> wrapper = WrapperUtil.createQueryWrapper(SysWarningJobParamEntity.class)
                .eq(SysWarningJobParamEntity::getJobId,jobDetails.getId());
        final List<WarningJobParamDTO> jobParams = jobParamMapper.selectList(wrapper).stream().map(paramEntity -> {
            WarningJobParamDTO jobParamDTO = new WarningJobParamDTO();
            BeanUtils.copyProperties(paramEntity, jobParamDTO);
            return jobParamDTO;
        }).collect(Collectors.toList());
        jobDetails.setJobParams(jobParams);
        return jobDetails;
    };

    // 查询模板变量信息
    Function<JobDetails, JobDetails> queryTemplateVariables = jobDetails -> {
        LambdaQueryWrapper<SysWarningJobPlaceholderConfigEntity> wrapper = WrapperUtil.createQueryWrapper(SysWarningJobPlaceholderConfigEntity.class)
                .eq(SysWarningJobPlaceholderConfigEntity::getJobId, jobDetails.getId());
        final List<JobTemplateVariable> jobTemplateVariables = placeholderConfigMapper.selectList(wrapper).stream().map(entity -> {
            JobTemplateVariable variable = new JobTemplateVariable();
            variable.setVariableCode(entity.getPlaceholderCode());
            variable.setVariableName(entity.getPlaceholderName());
            variable.setVariableType(entity.getType());
            return variable;
        }).collect(Collectors.toList());
        jobDetails.setJobTemplateVariables(jobTemplateVariables);
        return jobDetails;
    };
   
    // 使用链式调用
    return queryJobBaseInfo
            .andThen(queryJobParams)
            .andThen(queryTemplateVariables)
            .apply(jobId);
}


public void delete(String jobId) {
    // 删除任务
    Consumer<String> deleteJob = id -> {
        SysWarningJobEntity jobEntity = new SysWarningJobEntity().setDeleteAttributesWithPrimaryKey(id);
        jobMapper.updateById(jobEntity);
    };
    //删除 任务参数
    Consumer<String> deleteJobParam = id -> {
        LambdaUpdateWrapper<SysWarningJobParamEntity> wrapper = WrapperUtil.createDeleteWrapper(SysWarningJobParamEntity.class)
                .eq(SysWarningJobParamEntity::getJobId, id);
        jobParamMapper.update(wrapper);
    };
    //删除 任务模版变量
    Consumer<String> deleteJobTemplateVar = id -> {
        LambdaUpdateWrapper<SysWarningJobPlaceholderConfigEntity> wrapper = WrapperUtil.createDeleteWrapper(SysWarningJobPlaceholderConfigEntity.class)
                .eq(SysWarningJobPlaceholderConfigEntity::getJobId, id);
        placeholderConfigMapper.update(wrapper);
    };
    deleteJob.andThen(deleteJobParam).andThen(deleteJobTemplateVar).accept(jobId);
}
Java 中的函数式编程探索 Java自Java8起通过引入Lambda表达式、函数接口和StreamsAPI,开始支持函数式编程(FP),尽管其设计根植于1990年代的硬件限制,导致在实现FP时面临挑战。Java的默认可变性与FP的不可变性原则相冲突,且其类型系统和集合设计对FP构成限制。然而,Java通过高阶函数、递归、闭包、惰性求值和柯里化等技术 阅读详情

相关推荐

高通 Gen AI 推理扩展 (GENIE)(5):实战指南与Engine API深度解析

本文深入解析高通Gen AI推理扩展(GENIE)的Engine API核心功能与实战应用,涵盖引擎实例化、多引擎动态切换、性能调优及跨平台部署等关键技巧。通过详细代码示例和性能数据,帮助开发者高效利用GENIE进行AI推理,提升应用性能与稳定性。

weixin_29065959的博客 465

Java函数式编程

函数式接口:有且仅有一个抽象方法的接口Java 中的函数式编程体现就是 Lambda 表达式,所以函数式接口就是可以适用于 Lambda 使用的接口只有确保接口中有且仅有一个抽象方法,Java 中的 Lambda 才能顺利地进行推导如何检测一个接口是不是函数式接口呢?放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败。

qq_49487356的博客 9414

松灵机器人——ROS下的CAN通讯调试(内含所需调用包,都是操作步骤)

松灵机器人——ROS下的CAN通讯调试(都是操作步骤) 1 代码包地址 scout_ros package:https://github.com/westonrobot/scout_ros.git ugv_sdk-main package:https://github.com/westonrobot/ugv_sdk webots package:https://cyberbotics.com/ 2 硬件准备 2.1 SCOUT MINI 小白车 + 尾部航空插头 + CAN_TO_USB适配器

weixin_48924581的博客 1万+

Java学习——函数式编程

Java学习笔记——函数式编程

weixin_44456914的博客 3860

振动能量采集技术:从原理到实战,破解物联网供电难题

能量采集技术旨在捕获环境中的废弃能量(如机械振动、热能、光能)并将其转化为电能,其核心原理在于通过压电、电磁、静电或摩擦电等物理效应实现能量形式的转换。这项技术的核心价值在于为物联网(IoT)中难以布线或更换电池的分布式传感器节点、植入式医疗设备等提供近乎永续的电力解决方案,从而解决物联网部署的“最后一米供电”瓶颈。其应用场景广泛覆盖工业预测性维护、结构健康监测、可穿戴设备及消费电子等领域。本文聚焦于振动能量采集这一细分方向,深入剖析了压电式、电磁式、电容式及摩擦纳米发电机(TENG)等主流技术路线的实战考

weixin_42660494的博客 569

用Python turtle库 绘制皮卡丘

Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x、纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行的路径上绘制了图形。 turtle基础知识参考: https://gitchat.blog.youkuaiyun.com/article/details/90696190 https://blog.csdn.ne...

qq_36295856的博客 2万+

JAVA基础 函数式编程

仅为个人学习使用。

,,,,,,, 3903

c++ pcl点云处理(2025 长期更新)

目录1.常用的点云文件2.认识点云的文件格式3.点云的数据结构4.输入输出(IO)5.KD树6.Oc树(八叉树)7.点云可视化8.点云滤波9.点云拟合分割10.点云与图像11.特征点与特征描述及提取12.点云配准13.点云曲面重建

twnkie的博客 2259

java -- 函数式编程

函数式编程

weixin_44966435的博客 1221

游戏玩家和排行数据抓取:使用 Python 爬虫抓取游戏中的玩家排名、角色数据和战绩

对于游戏开发者、分析师和玩家本身来说,抓取游戏中的玩家排名、角色数据和战绩信息是一项至关重要的任务。Python提供了强大的爬虫库和数据处理工具,可以帮助我们高效地抓取和分析游戏数据,为游戏分析师、开发者以及玩家本身提供有价值的数据支持。通过本篇博客,我们学习了如何使用Python爬虫技术抓取游戏中的玩家排名、角色数据和战绩。本篇博客将详细介绍如何使用Python编写爬虫来抓取游戏中的玩家排名、角色数据和战绩,并结合最新的技术来实现高效的数据抓取与处理。为了方便后续的数据处理,我们将抓取的数据保存到。

2201_76125261的博客 946

数据分析案例-2024年裁员数据集可视化分析

本实验数据集来源于Kaggle,原始数据集为2020-2024年裁员数据,共有3577条,12个变量,该数据集提供了不同公司的裁员信息。它包括以下几栏:Company:裁员发生的公司名称。Location_HQ:公司总部位置。Industry:公司所属的行业或部门。Laid_Off_Count:公司解雇的员工数量。Percentage:公司员工被解雇的百分比。Date:裁员发生的日期。Source:信息来源网址。Funds_Raised:公司募集资金的信息。

m0_64336780的博客 1万+

Java函数式编程详解

Java从1.8以后引入了函数式编程,这是很大的一个改进。函数式编程的优点在提高编码的效率,增强代码的可读性。本文历时两个多月一点点写出来,即作为心得,亦作为交流。 1.Java函数式编程的语法: 使用Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept,这个方法只有输入而无输出也就是说这个方法无返回值。 现在我们要定义一个Consumer接口的实例化对象,传统的方式是...

陈大伟的博客 3万+

ArcGIS实验教程——实验十九:网络分析(最短路径实现)

一、实验描述 网络分析模块用于实现基于网络数据集的网络分析功能,包括路径分析、服务区分析、最近设施点分析、OD成本矩阵分析、多路径配送分析、位置分配分析和高级网络的管理与创建等。 网络数据集不同于几何网络,是一种高级的连接模型,能够展示复杂的细节,拥有丰富的网络属性模型,可以模拟网络阻力、网络限制以及网络层次等。 本实验重点演示网络分析中最短路径的实现过程。 二、实验内容 1、网络数据集...

智慧空间实验室 5684

Java函数式编程入门

函数式编程在Java中不仅能提高代码的简洁性和可读性,还能在处理数据流、并行计算等场景中发挥重要作用。通过掌握Lambda表达式、Stream API、Optional以及其他相关技术,并结合实际业务场景的应用,你将能够更高效地开发出安全、稳定和可维护的系统。建议在日常项目中逐步引入函数式编程思想,从简单的集合操作开始,逐步探索更多高级特性,并结合代码评审和测试不断完善实践经验。/*** 函数式编程*//*** Function<T, R>:接受T类型的参数,返回R类型的结果。

zjh285077371的专栏 1781

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

java函数式编程

函数式接口是只包含一个抽象方法的接口(不包括Object类中的方法)。这样的接口可以被隐式地转换为Lambda表达式。Stream API 提供了一种高效且易于使用的方式来处理集合(Collection)和数组。Stream操作分为中间操作(Intermediate Operations)和终端操作(Terminal Operations)。方法引用是Lambda表达式的一种简洁写法,它允许你直接引用已存在的方法或构造器。

2401_83447580的博客 1565

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Java8函数式编程

最近使用lambda表达式,感觉使用起来非常舒服,箭头函数极大增强了代码的表达能力。于是决心花点时间深入地去研究一下java8的函数式。 (想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!) 一、lambda表达式 先po一个最经典的例子——线程 public static void main(String[] args) { // Java7 n...

wanghao112956的博客 2万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java 中的函数式编程详解

摘要 Java 8 引入函数式编程特性,包括 Lambda 表达式、函数式接口、方法引用和 Stream API,使代码更简洁高效。函数式接口(如 Function、Consumer)是基础,Lambda 表达式简化匿名函数写法,方法引用进一步优化语法。Stream API 支持链式数据操作,结合过滤、映射等中间操作和收集等终端操作,提升数据处理能力。Optional 类帮助避免空指针异常。函数式编程优势包括代码简洁、可读性强和并行处理能力,但也存在性能开销和学习成本。实战示例展示了如何用 Stream 处

2503_92145588的博客 1904

Java如何支持函数式编程?

简介:Java是面向对象的语言,无法直接调用一个函数。Java 8开始,引入了函数式编程接口与Lambda表达式,便于开发者写出更少更优雅的代码。什么是函数式编程?函数式编程的特点是什么?本文通过代码实例,从Stream类、Lambda表达式和函数接口这三个语法概念来分享Java对函数式编程的支持。背景在很长的一段时间里,Java一直是面向对象的语言,一切皆对象,如果想要调用一个函数,函数必须属于一个类或对象,然后在使用类或对象进行调用。但是在其它的编程语言中,如JS、C++,我们可以直接写一个函数,然后在

阿里云开发者 4888
上一篇: Spring 依赖注入(Dependency Injection)
下一篇: Web 下载文件请求
知楠行易
博客等级 码龄9年 320粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值