Java 中 List 分片的 5 種方法!

前些天在實(shí)現(xiàn) MyBatis 批量插入時(shí)遇到了一個(gè)問題,當(dāng)批量插入的數(shù)據(jù)量比較大時(shí),會(huì)導(dǎo)致程序執(zhí)行報(bào)錯(cuò),如下圖所示:


原因是 MySQL 只能執(zhí)行一定長(zhǎng)度的 SQL 語(yǔ)句,但當(dāng)插入的數(shù)據(jù)量較多時(shí),會(huì)生成一條很長(zhǎng)的 SQL,這樣程序在執(zhí)行時(shí)就會(huì)報(bào)錯(cuò)。

要解決這個(gè)問題,有兩種方法:第一,設(shè)置 MySQL 可以執(zhí)行 SQL 的最大長(zhǎng)度;第二,將一個(gè)大 List 分成 N 個(gè)小 List 進(jìn)行。由于無(wú)法準(zhǔn)確的界定程序中最大的 SQL 長(zhǎng)度,所以最優(yōu)的解決方案還是第二種,于是就有了今天的這篇文章。java學(xué)習(xí)交流737251827

簡(jiǎn)介

將一個(gè) List 分成多個(gè)小 List 的過程,我們稱之為分片,當(dāng)然也可以叫做“List 分隔”,選一個(gè)你喜歡的、好理解的叫法就行。

在 Java 中,分片的常見實(shí)現(xiàn)方法有以下幾種:

使用 Google 的 Guava 框架實(shí)現(xiàn)分片;

使用 Apache 的 commons 框架實(shí)現(xiàn)分片;

使用國(guó)產(chǎn)神級(jí)框架 Hutool 實(shí)現(xiàn)分片;

使用 JDK 8 中提供 Stream 實(shí)現(xiàn)分片;

自定義分片功能。

接下來(lái)我們分別來(lái)看。

1.Google Guava

先在項(xiàng)目的 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 方法即可實(shí)現(xiàn)分片,如下代碼所示:

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( "唐僧,悟空,八戒,沙僧,曹操,劉備,孫權(quán)".split(","));

public static void main(String[] args) {

// 集合分片

List<List<String>> newList = Lists.partition(OLD_LIST, 3);

// 打印分片集合

newList.forEach(i -> { System.out.println("集合長(zhǎng)度:" + i.size());

});

}}

以上代碼的執(zhí)行結(jié)果如下圖所示:


2.apache commons

先在項(xiàng)目的 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 方法即可實(shí)現(xiàn)分片,如下代碼所示:

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( "唐僧,悟空,八戒,沙僧,曹操,劉備,孫權(quán)".split(","));

public static void main(String[] args) {

// 集合分片

List<List<String>> newList = ListUtils.partition(OLD_LIST, 3);

newList.forEach(i -> { System.out.println("集合長(zhǎng)度:" + i.size());

});

}}

以上代碼的執(zhí)行結(jié)果如下圖所示:


3.Hutool

先在項(xiàng)目的 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 方法即可實(shí)現(xiàn)分片,如下代碼所示:


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( "唐僧,悟空,八戒,沙僧,曹操,劉備,孫權(quán)".split(","));

public static void main(String[] args) {

// 分片處理

List<List<String>> newList = ListUtil.partition(OLD_LIST, 3);

newList.forEach(i -> { System.out.println("集合長(zhǎng)度:" + i.size());

});

}}


以上代碼的執(zhí)行結(jié)果如下圖所示:


4.JDK

Stream 通過 JDK 8 中的? Stream 來(lái)實(shí)現(xiàn)分片就無(wú)需添加任何框架了,具體的實(shí)現(xiàn)代碼如下:

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 的數(shù)據(jù)分別分為兩組

? ? ? ?Map<Boolean, List<Integer>> newMap = OLD_LIST.stream().collect(

? ? ? ? ? ? ? ?Collectors.partitioningBy(i -> i > 3)

? ? ? ?);

? ? ? ?// 打印結(jié)果

? ? ? ?System.out.println(newMap);

? ?}

}

以上代碼的執(zhí)行結(jié)果如下圖所示:


此方式的優(yōu)點(diǎn)的無(wú)需添加任何框架,但缺點(diǎn)是只能實(shí)現(xiàn)簡(jiǎn)單的分片(將一個(gè) List 分為兩個(gè)),并且要有明確的分片條件。比如本篇案例中設(shè)置的分片條件就是數(shù)組是否大于 3,如果大于 3 就會(huì)被歸為一組,否則就會(huì)被分到另一組。

5.自定義分片

如果你不想引入第三方框架,并且使用 Stream 也無(wú)法滿足你的需求,你就可以考慮自己寫代碼來(lái)實(shí)現(xiàn)分片功能了。因?yàn)榇朔绞讲怀S?,所以咱們這里只給出關(guān)鍵方法。

自定義分片功能的關(guān)鍵實(shí)現(xiàn)方法是 JDK 自帶的 subList 方法,如下圖所示:


使用示例如下:

import java.util.Arrays;

import java.util.List;

public class App {

? ? private static final List<String> _OLD_LIST = Arrays.asList(

? ? ? ? ? ? "唐僧,悟空,八戒,沙僧,曹操,劉備,孫權(quán)".split(","));

? ? public static void main(String[] args) {

? ? ? ? // 集合分隔

? ? ? ? List<String> list = _OLD_LIST.subList(0, 3);

? ? ? ? // 打印集合中的元素

? ? ? ? list.forEach(i -> {

? ? ? ? ? ? System.out.println(i);

? ? ? ? });

? ? }

}

以上代碼的執(zhí)行結(jié)果如下圖所示:


總結(jié)

本文介紹了 5 種 List 分片的實(shí)現(xiàn)方法,其中最方便的實(shí)現(xiàn)方式是引入第三方框架,比如 Google 的 Guava、Apache 的 Commons 或者是國(guó)產(chǎn)開源的 Hutool 都可以,當(dāng)然如果你的項(xiàng)目已經(jīng)包含了以上任意一種,直接使用就行了。如果是簡(jiǎn)單的分片就可以考慮使用 JDK 的 Stream 或者是 List 內(nèi)置的 subList 方法來(lái)實(shí)現(xiàn)分片功能了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容