JAVA设计模式-大集合数据拆分
背景
我们在做软件开发时,经常会遇到把大集合的数据,拆分成子集合处理。例如批量数据插入数据库时,一次大约插入5000条数据比较合理,但是有时候待插入的数据远远大于5000条。这时候就需要进行数据拆分。数据拆分基本逻辑并不复杂,下面尝试把数据拆分逻辑封装一下。
拆分逻辑
拆分过程唯一要求就是数据不能遗漏,也不能重复处理。
- 定义子集合大小
- 遍历源数据集合,达到一个子集合大小,
- 根据业务需要开始处理子集合数据
- 直到处理完所有数据
代码
先实现基本功能代码
/*** @param dataList 原数据集合* @param subSize 子集合size* @throws Exception*/public static <T> void processdSubData(List<T> dataList, int subSize) throws Exception {//子集合对象List<T> subDataList = new ArrayList<>();//计数变量int count = 0;for (T t : dataList) {subDataList.add(t);count++;//累计子集合数据数量if (count >= subSize) {//这里可以使用等号==,个人习惯使用大于等于>=try {//处理子集合数据//doSomeThing(subDataList);} catch (Exception e) {throw e;} finally {//清空计数变量和子集合count = 0;subDataList.clear();}}}//这里的剩余数据处理,非常容易遗漏,这也是为什么要封装公共代码的一个原因//封装成公共代码后,就不用担心遗漏这一部分数据if (subDataList.size() > 0) {//最后一次剩余数据量小于subSize,这里再处理一次try {//处理子集合数据//doSomeThing(subDataList);} catch (Exception e) {throw e;}}}
以上的代码,逻辑清晰且没有复杂的索引计算,是个比较好的实现。但是代码没有通用性,每次遇到数据拆分,都要写一遍拆分呢逻辑,写的多了难免出问题。仔细看下代码,除了处理子集合数据的业务代码方法,其他代码都是一样的。下面改造一下,子集合数据的业务方法由外部传入。那么拆分逻辑部分就可以通用,不用担心出问题了。
新实现
- 业务处理接口
package cn.com.soulfox.common.functions.splitdata;import java.util.List;/**** 子数据集合业务数据处理接口* @create 2024/6/24 10:21*/
@FunctionalInterface//函数式接口,只有一个抽象方法
public interface SplitDataCallback<T> {void splitDataProcess(List<T> subDataList);
}
- 拆分工具类
package cn.com.soulfox.common.functions.splitdata;import java.util.List;/*** 大集合拆分处理** * @create 2024/6/24 10:35*/
public class SplitDataListUtil {/*** @param dataList 待拆分数据集合* @param subSize 子集合的size* @param callback 子集合数据处理类* @throws Exception*/public static <T> void processData(List<T> dataList, int subSize, SplitDataCallback<T> callback) throws Exception {//如果不做成公共代码,下面的判空的代码,忙的时候就不会写了吧 -:)if (callback == null) {//处理类为空return;}if (dataList == null || dataList.isEmpty()) {//数据集合为空return;}if (subSize <= 0) {//子集长度小于等于 0return;}if (subSize >= dataList.size()) {//子集长度大于等于原集合,不需要拆分,直接处理try {callback.splitDataProcess(dataList);} catch (Exception e) {System.out.println("处理子数据集失败:"+e.getMessage());throw e;}return;}processdSubData(dataList, subSize, (SplitDataCallback<T>) callback);}/*** @param dataList 原数据集合* @param subSize 子集合size* @param callback 子集合数据处理类* @throws Exception*/private static <T> void processdSubData(List<T> dataList, int subSize, SplitDataCallback<T> callback) throws Exception {//子集合对象List<T> subDataList = new ArrayList<>();int count = 0;for (T t : dataList) {subDataList.add(t);//计数count++;if (count >= subSize) {//这里可以使用等号==,个人习惯使用大于等于>=//数量达到subSize,做一次处理try {callback.splitDataProcess(subDataList);} catch (Exception e) {System.out.println("处理子数据集失败:"+e.getMessage());throw e;} finally {//清空计数变量和子集合count = 0;subDataList.clear();}}}//这里的剩余数据处理,非常容易遗漏,这也是为什么要封装公共代码的一个原因//封装成公共代码后,就不用担心遗漏这一部分数据if (subDataList.size() > 0) {//最后一次剩余数据量小于subSize,这里再处理一次try {callback.splitDataProcess(subDataList);} catch (Exception e) {System.out.println("处理子数据集失败:"+e.getMessage());throw e;}}}
}
- 单元测试
package cn.com.soulfox.common.functions.splitdata;import org.junit.Before;
import org.junit.Test;import java.util.Arrays;
import java.util.List;/**** @create 2024/6/24 15:50*/
public class SplitDataListUtilTest {private List<String> dataList;@Beforepublic void setup(){//准备数据dataList = Arrays.asList("a","b","c","1","2");}@Testpublic void test(){//定义子集合sizeint subSize = 2;//业务逻辑比较简单, 可直接写业务代码try {SplitDataListUtil.processData(this.dataList, subSize,(subDataList -> {System.out.println("简单业务代码++++");subDataList.forEach(data ->{System.out.println("简单业务代码: "+data);});}));} catch (Exception e) {e.printStackTrace();}}
}

- 业务处理逻辑复杂
实现类
package cn.com.soulfox.common.functions.splitdata;import java.util.List;/*** 业务逻辑复杂* @create 2024/6/24 16:05*/
public class ComplexBusinessImpl implements SplitDataCallback<String>{@Overridepublic void splitDataProcess(List<String> subDataList) {System.out.println("复杂业务代码++++");subDataList.forEach(data ->{System.out.println("复杂业务代码: "+data);});}}
加一个测试方法
@Testpublic void testComplexBusiness(){//定义子集合sizeint subSize = 2;//业务逻辑比较复杂, 创建接口实现类ComplexBusinessImpl 传入方法中ComplexBusinessImpl complexBusiness = new ComplexBusinessImpl();try {SplitDataListUtil.processData(this.dataList, subSize, complexBusiness);} catch (Exception e) {e.printStackTrace();}}
测试结果

总结一下。。。
拆分数据功能并不复杂,封装公共代码,也看不什么好处,实际开发的时候直接复制拆分代码即可。
这里主要是为了提出一种,设计通用功能的思路。任何功能,总有一部分结构性代码是不变的,变化的是业务处理代码。例如,上面的例子中,把大集合拆分成小集合的逻辑是不变的,变化的是数据处理逻辑。把不变的部分抽象出来封装成公共代码,同时把一些判空,边界数据做一下统一处理,这样就会在提高代码复用率的同时,减少出错几率。
相关文章:
JAVA设计模式-大集合数据拆分
背景 我们在做软件开发时,经常会遇到把大集合的数据,拆分成子集合处理。例如批量数据插入数据库时,一次大约插入5000条数据比较合理,但是有时候待插入的数据远远大于5000条。这时候就需要进行数据拆分。数据拆分基本逻辑并不复杂&…...
如何使用sr2t将你的安全扫描报告转换为表格格式
关于sr2t sr2t是一款针对安全扫描报告的格式转换工具,全称为“Scanning reports to tabular”,该工具可以获取扫描工具的输出文件,并将文件数据转换为表格格式,例如CSV、XLSX或文本表格等,能够为广大研究人员提供一个…...
ansible自动化运维,(2)ansible-playbook
三种常见的数据格式: XML:可扩展标记语言,用于数据交换和配置 JSON:对象标记法,主要用来数据交换或配置,不支持注释 YAML:不是一种标记语言,主要用来配置,大小写敏感&…...
一分钟学习数据安全—自主管理身份SSI分布式标识DID介绍
SSI标准化的两大支柱,一个是VC,之前简单介绍过,另一个就是DID。基本层次上,DID就是一种新型的全局唯一标识符,跟浏览器的URL没有什么不同。深层次上,DID是互联网分布式数字身份和PKI新层级的原子构件。 一…...
[单master节点k8s部署]11.服务service
service service是一个固定接入层,客户端 可以访问service的ip和端口,访问到service关联的后端pod,这个service工作依赖于dns服务(coredns) 每一个k8s节点上都有一个组件叫做kube-proxy,始终监视着apiser…...
ES6面试题——箭头函数和普通函数有什么区别
1. this指向问题 <script> let obj {a: function () {console.log(this); // 打印出:{a: ƒ, b: ƒ}},b: () > {console.log(this); // 打印出Window {window: Window, self: Window,...}}, }; obj.a(); obj.b(); </script> 箭头函数中的this是在箭…...
WordPress中文网址导航栏主题风格模版HaoWa
模板介绍 WordPress响应式网站中文网址导航栏主题风格模版HaoWa1.3.1源码 HaoWA主题风格除行为主体导航栏目录外,对主题风格需要的小控制模块都开展了敞开式的HTML在线编辑器方式的作用配备,另外预埋出默认设置的编码构造,便捷大伙儿在目前…...
ThreadPoolExecutor基于ctl变量的声明周期管理
个人博客 ThreadPoolExecutor基于ctl变量的声明周期管理 | iwts’s blog 总集 想要完整了解下ThreadPoolExecutor?可以参考: 基于源码详解ThreadPoolExecutor实现原理 | iwts’s blog ctl字段的应用 线程池内部使用一个变量ctl维护两个值ÿ…...
运维锅总详解Prometheus
本文尝试从Prometheus简介、架构、各重要组件详解、relable_configs最佳实践、性能能优化及常见高可用解决方案等方面对Prometheus进行详细阐述。希望对您有所帮助! 一、Prometheus简介 Prometheus 是一个开源的系统监控和报警工具,最初由 SoundCloud …...
深入解析Tomcat:Java Web服务器(上)
深入解析Tomcat:Java Web服务器(上) Apache Tomcat是一个开源的Java Web服务器和Servlet容器,用于运行Java Servlets和JavaServer Pages (JSP)。Tomcat在Java Web应用开发中扮演着重要角色。本文将详细介绍Tomcat的基本概念、安装…...
【第9章】MyBatis-Plus持久层接口之SimpleQuery
文章目录 前言一、使用步骤1.引入 SimpleQuery 工具类2.使用 SimpleQuery 进行查询 二、使用提示三、功能详解1. keyMap1.1 方法签名1.2 参数说明1.3 使用示例1.4 使用提示 2. map2.1 方法签名2.2 参数说明2.3 使用示例2.4 使用提示 3. group3.1 方法签名3.2 参数说明3.3 使用示…...
一文带你了解乐观锁和悲观锁的本质区别!
文章目录 悲观锁是什么?乐观锁是什么?如何实现乐观锁?什么是CAS应用局限性ABA问题是什么? 悲观锁是什么? 悲观锁它总是假设最坏的情况,它会认为共享资源在每次被访问的时候就会出现线程安全问题࿰…...
Android Studio环境搭建(4.03)和报错解决记录
1.本地SDK包导入 安装好IDE以及下好SDK包后,先不要管IDE的引导配置,直接新建一个新工程,进到开发界面。 SDK路径配置:File---->>Other Settings---->>Default Project Structure 拷贝你SDK解压的路径来这,…...
基于协同过滤的电影推荐与大数据分析的可视化系统
基于协同过滤的电影推荐与大数据分析的可视化系统 在大数据时代,数据分析和可视化是从大量数据中提取有价值信息的关键步骤。本文将介绍如何使用Python进行数据爬取,Hive进行数据分析,ECharts进行数据可视化,以及基于协同过滤算法…...
修复vcruntime140.dll方法分享
修复vcruntime140.dll方法分享 最近在破解typora的时候出现了缺失vcruntime140.dll文件的报错导致软件启动失败。所以找了一番资料发现都不是很方便的处理,甚至有的dll处理工具还需要花钱????,我本来就是为…...
PostgreSQL的系统视图pg_stat_wal_receiver
PostgreSQL的系统视图pg_stat_wal_receiver 在 PostgreSQL 中,pg_stat_wal_receiver 视图提供了关于 WAL(Write-Ahead Logging)接收进程的统计信息。WAL 接收器是 PostgreSQL 集群中流复制的一部分,它在从节点中工作,…...
Qt之Pdb生成及Dump崩溃文件生成与调试(含注释和源码)
文章目录 一、Pdb生成及Dump文件使用示例图1.Pdb文件生成2.Dump文件调试3.参数不全Pdb生成的Dump文件调试 二、个人理解1.生成Pdb文件的方式2.Dump文件不生产的情况 三、源码Pro文件mian.cppMainWindowUi文件 总结 一、Pdb生成及Dump文件使用示例图 1.Pdb文件生成 下图先通过…...
视频号视频怎么保存到手机,视频号视频怎么保存到手机相册里,苹果手机电脑都可以用
随着数字媒体的蓬勃发展,视频已成为我们日常生活中不可或缺的一部分。视频号作为众多视频分享平台中的一员,吸引了大量用户上传和分享各类精彩视频。然而,有时我们可能希望将视频号上的视频下载下来,以下将详细介绍如何将视频号的视频。 方法…...
Softmax函数的作用
Softmax 函数主要用于多类别分类问题,它将输入的数值转换为概率分布。 具体来说,对于给定的输入向量 x [x_1, x_2,..., x_n] ,Softmax 函数的输出为 y [y_1, y_2,..., y_n] ,其中: 这样,Softmax 函数的输…...
cesium 添加 Echarts 图层(空气质量点图)
cesium 添加 Echarts 图层(下面附有源码) 1、实现思路 1、在scene上面新增一个canvas画布 2、通坐标转换,将经纬度坐标转为屏幕坐标来实现 3、将ecarts 中每个series数组中元素都加 coordinateSystem: ‘cesiumEcharts’ 2、示例代码 <!DOCTYPE html> <html lan…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
