JAVA设计模式-大集合数据拆分

news2024/11/24 20:06:37

背景

  我们在做软件开发时,经常会遇到把大集合的数据,拆分成子集合处理。例如批量数据插入数据库时,一次大约插入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) {
            //子集长度小于等于 0
            return;
        }
		
        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;

    @Before
    public void setup(){
        //准备数据
        dataList = Arrays.asList("a","b","c","1","2");
    }

    @Test
    public void test(){
        //定义子集合size
        int 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>{

    @Override
    public void splitDataProcess(List<String> subDataList) {
        System.out.println("复杂业务代码++++");
        subDataList.forEach(data ->{
            System.out.println("复杂业务代码: "+data);
        });
    }

}

加一个测试方法

	@Test
    public void testComplexBusiness(){
        //定义子集合size
        int subSize = 2;
        //业务逻辑比较复杂, 创建接口实现类ComplexBusinessImpl 传入方法中
        ComplexBusinessImpl complexBusiness = new ComplexBusinessImpl();
        try {
            SplitDataListUtil.processData(this.dataList, subSize, complexBusiness);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

测试结果
复杂业务逻辑

总结一下。。。

  拆分数据功能并不复杂,封装公共代码,也看不什么好处,实际开发的时候直接复制拆分代码即可。
  这里主要是为了提出一种,设计通用功能的思路。任何功能,总有一部分结构性代码是不变的,变化的是业务处理代码。例如,上面的例子中,把大集合拆分成小集合的逻辑是不变的,变化的是数据处理逻辑。把不变的部分抽象出来封装成公共代码,同时把一些判空,边界数据做一下统一处理,这样就会在提高代码复用率的同时,减少出错几率。

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

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

相关文章

复分析——第9章——椭圆函数导论(E.M. Stein R. Shakarchi)

第 9 章 椭圆函数导论 (An Introduction to Elliptic Functions) The form that Jacobi had given to the theory of elliptic functions was far from perfection; its flaws are obvious. At the base we find three fundamental functions sn, cn and dn. These functio…

一款轻量级的WPF UI库---Adonis UI

Adonis UI适用于 WPF 应用程序的轻型 UI 工具包,提供经典但增强的 Windows 视觉对象 组件内容 几乎所有 WPF 控件的模板的默认样式为方便起见,可根据需要使用两种配色方案(浅色和深色),也可用于自定义样式支持在运行时更改配色方案支持其他自定义配色方案提供水印等功能的…

华为BGP路由实验基础1------用物理口建立对等体

1.用物理口做BGP建立对等体建立BGP连接 实验拓扑&#xff1a; 实验步骤&#xff1a; 1.完成基本配置 sys [Huawei]sys AR1 [AR1]undo in e [AR1]int g0/0/0 [AR1-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [AR1-GigabitEthernet0/0/0]q [AR1] sys [Huawei]sys AR2 [AR2]undo i…

2024年危化品安全员生产单位(生产管理人员)考试精选题库

31.《危险化学品安全管理条例》所称重大危险源,是指生产、储存、使用或者搬运危险化学品,且危险化学品的数量等于或者超过&#xff08;&#xff09;的单元(包括场所和设施)。 A.标准 B.一定量 C.临界量 答案&#xff1a;C 32.《危险化学品生产企业安全生产许可证实施办法》…

Sui创始团队在竞速环节中的快问快答

在Sui Basecamp活动期间&#xff0c;Sui区块链的最初贡献者在Oracle红牛赛车模拟器上展示了他们的技术能力&#xff0c;在驾驶圈时回答了有关Sui的问题。 Evan Cheng&#xff08;又名Revvin’ Evan&#xff09;在解释Mysticeti创下区块链最终性记录的同时保持着他的驾驶线路。…

C++——string类用法指南

一、前言 在C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需要用户自己管理&#xff0c;稍…

Linux—系统安全及应用

目录 一、账号安全控制 1、系统账号清理 1.1、将用户账号设置为无法登录 1.2、锁定长期不使用的账号 1.3、删除无用的账号 1.4、锁定账号文件passwd、shadow 2、密码安全控制 2.1、设置密码有效期 2.1.1、适用于新建用户 2.1.2、适用于已有用户 2.2、强制用户下次登录…

Python学习笔记26:进阶篇(十五)常见标准库使用之性能测试cProfile模块学习使用

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 本文主要…

Qt—贪吃蛇项目(由0到1实现贪吃蛇项目)

用Qt实现一个贪吃蛇项目 一、项目介绍二、游戏大厅界面实现2.1完成游戏大厅的背景图。2.2创建一个按钮&#xff0c;给它设置样式&#xff0c;并且可以跳转到别的页面 三、难度选择界面实现四、 游戏界面实现五、在文件中写入历史战绩5.1 从文件里提取分数5.2 把贪吃蛇的长度存入…

华为OceanStor磁盘阵列存储恢复出厂设置命令 LUN不处于在线状态,不能执行此操作解决方案

环境 OceanStor S2600T V2老版本 客户现场有一台Oceanstor 2600 V2的存储&#xff0c;因和另一台磁盘扩展框做了跨设备LUN需要进行配置清除&#xff0c;配置结束后需要重新划分存储空间并对接服务器&#xff0c;保证业务能够正常上线&#xff01;在清除配置回退的过程中&#…

Firefox 编译指南2024 Windows10篇- 编译Firefox(三)

1.引言 在成功获取了Firefox源码之后&#xff0c;下一步就是将这些源码编译成一个可执行的浏览器。编译是开发流程中的关键环节&#xff0c;通过编译&#xff0c;我们可以将源代码转换为可执行的程序&#xff0c;测试其功能&#xff0c;并进行必要的优化和调试。 对于像Firef…

Milvus【部署 01】向量数据库Milvus在Linux环境下的在线+离线安装

向量数据库Milvus在Linux环境下的在线离线安装 1.千问简介2.在线安装2.离线安装 1.千问简介 Milvus 是一款专为处理高维向量数据设计的开源云原生数据库&#xff0c;旨在满足海量向量数据的实时召回需求。它由 Zilliz 公司开发并维护&#xff0c;基于Apache许可证2.0版本发布。…

选择适合你的8款原型设计工具

随着互联网的飞速发展&#xff0c;设计行业逐渐成为近年来的热门职业。设计师们需要的掌握的技能也越来越多&#xff0c;例如海报设计、名片设计、产品设计、网页设计等。产品原型设计就是产品设计中非常重要的一个阶段&#xff0c;主要目的是帮助用户更容易了解产品设计的思路…

YouTube广告投放指南:如何投放 YouTube视频广告

在海外广告投放中&#xff0c;YOutube是重要的渠道之一。这篇文章Maskfog将为你介绍Youtube广告类型以及广告投放流程&#xff0c;继续看下去&#xff01; YouTube 视频广告的类型 1.信息流视频广告 信息流视频广告显示在 YouTube 主页、搜索结果页面上&#xff0c;并作为 Yo…

【pytorch10】统计属性

常见统计属性 norm&#xff08;范数&#xff09;mean,sumprodmax&#xff0c;min&#xff0c;argmin&#xff0c;argmaxkthvalue&#xff0c;topk kthvalue求第几个的位置和第几个的值 topk求top几的这样的一个数值 norm范数 这里的norm表达的是范数的意思&#xff0c;norma…

wait/notify 的原理

目录 一、wait/notify 的原理 二、虚假唤醒&#xff08;错误唤醒&#xff09; 三、使用 wait/notify 的正确姿势 一、wait/notify 的原理 1. owner 线程发现有条件不满足&#xff0c;调用 wait() 进入 Monitor 的 WaitSet 等待&#xff0c;切换为 Waiting 状态 2. 问题&…

老生常谈问题之什么是缓存穿透、缓存击穿、缓存雪崩?举个例子你就彻底懂了!!

老生常谈问题之什么是缓存穿透、缓存击穿、缓存雪崩&#xff1f;举个例子你就彻底懂了&#xff01;&#xff01; 缓存穿透发生场景解决方案 缓存击穿解决方案 缓存雪崩发生场景解决方案 总结三者区分三者原因三者解决方案 想象一下&#xff0c;你开了一家便利店&#xff0c;店里…

Springboot Mybatis 多数据源配置以及使用

在Spring Boot中配置MyBatis的多数据源是一个常见需求&#xff0c;尤其是在需要连接多个数据库时&#xff0c;下面是详细的步骤指南。 引入依赖 首先&#xff0c;在你的pom.xml文件中添加Spring Boot、MyBatis和数据库连接的相关依赖。例如&#xff0c;如果你使用的是MySQL数…

Boosted Trees 介绍

Boosted Trees 介绍 文章目录 Boosted Trees 介绍监督学习要素模型和参数目标函数&#xff1a;训练损失 正则化为什么介绍一般原则&#xff1f; 决策树集成Tree BoostingAdditive TrainingModel ComplexityThe Structure ScoreLearn the tree structure 关于 XGBoost 的最后话…

Kotlin vs Java:深入解析两者之间的最新差异与优劣(全面指南)

文章目录 1. 概述2. 语法简洁性3. 空安全4. 扩展函数5. 协程6. 数据类7. 智能类型转换8. 默认参数与命名参数9. 无 checked exceptions10. 单例模式总结 &#x1f389;欢迎来到Java学习路线专栏~探索Java中的静态变量与实例变量 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨…