集合 List 分片的 5 种实现

678f025a28f578805ede1b1853fee2a9.png

作者 | 磊哥

来源 | Java中文社群(ID:javacn666)

转载请联系授权(微信ID:GG_Stone)

前些天在实现 MyBatis 批量插入时遇到了一个问题,当批量插入的数据量比较大时,会导致程序执行报错,如下图所示:

bf29bf9a1c646d15090bd63c3844e6a3.png原因是 MySQL 只能执行一定长度的 SQL 语句,但当插入的数据量较多时,会生成一条很长的 SQL,这样程序在执行时就会报错。

要解决这个问题,有两种方法:第一,设置 MySQL 可以执行 SQL 的最大长度;第二,将一个大 List 分成 N 个小 List 进行。由于无法准确的界定程序中最大的 SQL 长度,所以最优的解决方案还是第二种,于是就有了今天的这篇文章。

简介

将一个 List 分成多个小 List 的过程,我们称之为分片,当然也可以叫做“List 分隔”,选一个你喜欢的、好理解的叫法就行。

在 Java 中,分片的常见实现方法有以下几种:

  1. 使用 Google 的 Guava 框架实现分片;

  2. 使用 Apache 的 commons 框架实现分片;

  3. 使用国产神级框架 Hutool 实现分片;

  4. 使用 JDK 8 中提供 Stream 实现分片;

  5. 自定义分片功能。

接下来我们分别来看。

1.Google Guava

先在项目的 pom.xml 中添加框架支持,增加以下配置:

<!-- google guava 工具类 -->
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.0.1-jre</version>
</dependency>

有了 Guava 框架之后,只需要使用 Lists.partition 方法即可实现分片,如下代码所示:

import com.google.common.collect.Lists;import java.util.Arrays;
import java.util.List;/*** Guava 分片*/
public class PartitionByGuavaExample {// 原集合private static final List<String> OLD_LIST = Arrays.asList("唐僧,悟空,八戒,沙僧,曹操,刘备,孙权".split(","));public static void main(String[] args) {// 集合分片List<List<String>> newList = Lists.partition(OLD_LIST, 3);// 打印分片集合newList.forEach(i -> {System.out.println("集合长度:" + i.size());});}
}

以上代码的执行结果如下图所示:

a25412f83464a9e49ddb227189b4a094.png

2.apache commons

先在项目的 pom.xml 中添加框架支持,增加以下配置:

<!-- apache 集合工具类 -->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version>
</dependency>

有了  commons 框架之后,只需要使用 ListUtils.partition 方法即可实现分片,如下代码所示:

import org.apache.commons.collections4.ListUtils;import java.util.Arrays;
import java.util.List;/*** commons.collections4 集合分片*/
public class PartitionExample {// 原集合private static final List<String> OLD_LIST = Arrays.asList("唐僧,悟空,八戒,沙僧,曹操,刘备,孙权".split(","));public static void main(String[] args) {// 集合分片List<List<String>> newList = ListUtils.partition(OLD_LIST, 3);newList.forEach(i -> {System.out.println("集合长度:" + i.size());});}
}

以上代码的执行结果如下图所示:

c9632e4f44a07c398665859ef92554c2.png

3.Hutool

先在项目的 pom.xml 中添加框架支持,增加以下配置:

<!-- 工具类 hutool -->
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.14</version>
</dependency>

有了 Hutool 框架之后,只需要使用 ListUtil.partition 方法即可实现分片,如下代码所示:

import cn.hutool.core.collection.ListUtil;import java.util.Arrays;
import java.util.List;public class PartitionByHutoolExample {// 原集合private static final List<String> OLD_LIST = Arrays.asList("唐僧,悟空,八戒,沙僧,曹操,刘备,孙权".split(","));public static void main(String[] args) {// 分片处理List<List<String>> newList = ListUtil.partition(OLD_LIST, 3);newList.forEach(i -> {System.out.println("集合长度:" + i.size());});}
}

以上代码的执行结果如下图所示:

e342938b35b7e70d8c3674d0db11903f.png

4.JDK

Stream 通过 JDK 8 中的  Stream 来实现分片就无需添加任何框架了,具体的实现代码如下:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** JDK Stream Partition*/
public class PartitionByStreamExample {// 原集合private static final List<Integer> OLD_LIST = Arrays.asList(1, 2, 3, 4, 5, 6);public static void main(String[] args) {// 集合分片:将大于 3 和小于等于 3 的数据分别分为两组Map<Boolean, List<Integer>> newMap = OLD_LIST.stream().collect(Collectors.partitioningBy(i -> i > 3));// 打印结果System.out.println(newMap);}
}

以上代码的执行结果如下图所示:

0f697782fdcd50ebeec6b5f22c6e55ed.png此方式的优点的无需添加任何框架,但缺点是只能实现简单的分片(将一个 List 分为两个),并且要有明确的分片条件。比如本篇案例中设置的分片条件就是数组是否大于 3,如果大于 3 就会被归为一组,否则就会被分到另一组。

5.自定义分片

如果你不想引入第三方框架,并且使用 Stream 也无法满足你的需求,你就可以考虑自己写代码来实现分片功能了。因为此方式不常用,所以咱们这里只给出关键方法。

自定义分片功能的关键实现方法是 JDK 自带的 subList 方法,如下图所示:

4ac5ad415e2d1da5ec3dccab0fe9c07e.png使用示例如下:

import java.util.Arrays;
import java.util.List;public class App {private static final List<String> _OLD_LIST = Arrays.asList("唐僧,悟空,八戒,沙僧,曹操,刘备,孙权".split(","));public static void main(String[] args) {// 集合分隔List<String> list = _OLD_LIST.subList(0, 3);// 打印集合中的元素list.forEach(i -> {System.out.println(i);});}
}

以上代码的执行结果如下图所示:

4525d43e09825e95cee598a36c1a0979.png

总结

本文介绍了 5 种 List 分片的实现方法,其中最方便的实现方式是引入第三方框架,比如 Google 的 Guava、Apache 的 Commons 或者是国产开源的 Hutool 都可以,当然如果你的项目已经包含了以上任意一种,直接使用就行了。如果是简单的分片就可以考虑使用 JDK 的 Stream 或者是 List 内置的 subList 方法来实现分片功能了。

2129e8e826e2efd77128c7b262ba80c5.gif

往期推荐

f8394a2f4890825a1686849e3d1a1f1c.jpeg

MyBatis原生批量插入的坑与解决方案!


bedf99e54da8b2d858d80fc3bbdd94cb.jpeg

4 种方法!检查字符串是否为合法的日期格式


7d790f33102fbf0a521c60e0c72669f7.jpeg

高并发下秒杀商品,必须知道的9个细节



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

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

相关文章

消失的死锁

问题描述 如果java层面发生了死锁&#xff0c;当我们使用jstack命令的时候其实是可以将死锁的信息给dump出来的&#xff0c;在dump结果的最后会有类似Found one Java-level deadlock:的关键字&#xff0c;接着会把发生死锁的线程的堆栈及对应的同步锁给打印出来&#xff0c;这次…

ruby 新建对象_Ruby中的面向对象编程

ruby 新建对象Before getting into understanding how Object-oriented programming is implemented in Ruby, let us first understand what Object Oriented means. 在了解如何在Ruby中实现面向对象的编程之前&#xff0c;让我们首先了解面向对象的含义。 Object-oriented p…

使用它给 ​xxl-job 添加任务,太爽了

xxl-job是一款非常优秀的任务调度中间件&#xff0c;轻量级、使用简单、支持分布式等优点&#xff0c;让它广泛应用在我们的项目中&#xff0c;解决了不少定时任务的调度问题。我们都知道&#xff0c;在使用过程中需要先到xxl-job的任务调度中心页面上&#xff0c;配置执行器ex…

dubboSPI机制浅谈

2019独角兽企业重金招聘Python工程师标准>>> &#xfeff;&#xfeff;&#xfeff;本文重点讲述SPI机制&#xff0c;从jdk和dubbo 1、jdk spi机制 2、dubbo spi实现 首先spi是什么&#xff1f; SPI是为某个接口寻找服务实现的机制。为了实现在模块装配的时候能不在…

python 类中静态变量_Python中的类或静态变量

python 类中静态变量Python类/静态变量 (Python Class / Static Variables) Class or Static variables are class-related variables that are shared among all objects but the instance or non-static variable is unique for each object. In Python, there is no need fo…

彻底搞懂 SpringBoot 中的 starter 机制

前言我们都知道&#xff0c;Spring的功能非常强大&#xff0c;但也有些弊端。比如&#xff1a;我们需要手动去配置大量的参数&#xff0c;没有默认值&#xff0c;需要我们管理大量的jar包和它们的依赖。为了提升Spring项目的开发效率&#xff0c;简化一些配置&#xff0c;Sprin…

android四大组件之Service 注册广播接收者

广播的注册一共有两种&#xff0c;一种就是用清单文件注册&#xff0c;还有另外一种就是用代码注册&#xff0c;代码注册比较灵活&#xff0c;可以在需要的时候注册&#xff0c;不需要的时候解除注册 用服务注册广播首先要开启服务&#xff0c; 然后在服务oncreate方法里注册广…

c ++向量库_将向量复制到C ++中的另一个向量

c 向量库The ways that we are using to copy vectors in C, are: 我们用于在C 中复制向量的方法是&#xff1a; Copy one vectors elements to another (Simple approach) 将一个向量的元素复制到另一个(简单方法) Copy vector by using an assignment operator 通过使用赋值…

Java 中验证时间格式的 4 种方法

大家好&#xff0c;今天咱们来讲一下&#xff0c;Java 中如何检查一个字符串是否是合法的日期格式&#xff1f;为什么要检查时间格式&#xff1f;后端接口在接收数据的时候&#xff0c;都需要进行检查。检查全部通过后&#xff0c;才能够执行业务逻辑。对于时间格式&#xff0c…

FreeSWITCH的TLS加密

听着很高大上&#xff08;实际也很实用&#xff09;的加密机制&#xff0c;在FreeSWITCH里配置支持竟然这么简单&#xff01; Greate FreeSWITCH and Greate Programmer&#xff01; ① cd /usr/local/freeswitch/bin&#xff08;以默认的安装路径为例&#xff09; ② 产生root…

kotlin 查找id_Kotlin程序查找Sphere的体积

kotlin 查找idFormula to find volume of Sphere: volume (4/3)*PI*r^3 查找球体体积的公式&#xff1a; volume (4/3)* PI * r ^ 3 Given the value of radius, we have to find the volume of Sphere. 给定半径的值&#xff0c;我们必须找到球体的体积。 Example: 例&#…

Redis 实现分布式锁的 7 种方案

前言日常开发中&#xff0c;秒杀下单、抢红包等等业务场景&#xff0c;都需要用到分布式锁。而Redis非常适合作为分布式锁使用。本文将分七个方案展开&#xff0c;跟大家探讨Redis分布式锁的正确使用方式。如果有不正确的地方&#xff0c;欢迎大家指出哈&#xff0c;一起学习一…

css复选框样式_使用CSS样式复选框

css复选框样式Introduction: 介绍&#xff1a; Sometimes we want to develop a website or web page that would contain a form and through that form, we want to get some information from the user. Now that information could be of any type depending on the kind …

大数据计算平台Spark内核全面解读

1、Spark介绍 Spark是起源于美国加州大学伯克利分校AMPLab的大数据计算平台&#xff0c;在2010年开源&#xff0c;目前是Apache软件基金会的顶级项目。随着Spark在大数据计算领域的暂露头角&#xff0c;越来越多的企业开始关注和使用。2014年11月&#xff0c;Spark在Daytona Gr…

javascript对话框_JavaScript中的对话框

javascript对话框JavaScript对话框 (JavaScript Dialog Boxes) Dialog boxes are a great way to provide feedback to the user when they submit a form. In JavaScript, there are three kinds of Dialog boxes, 对话框是向用户提交表单时提供反馈的好方法。 在JavaScript中…

排查死锁的 4 种工具,秀~

作者 | 磊哥来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;死锁&#xff08;Dead Lock&#xff09;指的是两个或两个以上的运算单元&#xff08;进程、线程或协程&#xff09;&#xf…

MySQL 常见的 9 种优化方法

大家好&#xff0c;我是磊哥&#xff01;今天给大家分享一些简单好用的数据库优化方式&#xff01;1、选择最合适的字段属性Mysql是一种关系型数据库&#xff0c;可以很好地支持大数据量的存储&#xff0c;但是一般来说&#xff0c;数据库中的表越小&#xff0c;在它上面执行的…

oracle中dbms_DBMS中的实例和架构

oracle中dbms1)实例 (1) Instances) What is the Instance? If we look towards it in real life, we refer instance as an occurrence of something at a particular moment of time. In Database Management system, there are a lot of changes occurring over time to th…

acess() 判断目录是否存在

acess()功能描述&#xff1a; 检查调用进程是否可以对指定的文件执行某种操作。 <pre lang"c" escaped"true">#include <unistd.h>int access(const char *pathname, int mode); </pre>参数说明&#xff1a;pathname: 需要测试的文件路径…

过滤器和拦截器的 5 个区别!

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;过滤器&#xff08;Filter&#xff09;和拦截器&#xff08;Interceptor&#xff09;都是基于 AOP&#xff08;Aspec…