「这是我参与2022首次更文挑战的第32天,活动详情查看:2022首次更文挑战」。
一、相关概念
不知道各位大佬在开发中有没有遇到过下面所说的这种情况,查询出一堆的数据后,这堆数据是一个List对象,对象中有一个属性id,我们需要通过id去查询另一个表的数据(为什么不关联查询,部分情况下不能关联查询,或者通过这个id需要执行一个多表关联的查询,关联在原来的表上导致查询速度太慢,需要优化)。此时如何处理呢?循环去查询,但如果List很长呢,就会导致查询数据超级慢。此时想到通过List获得一个id的list,在sql中通过in进行查询。但如果id的list数量很多,可能会导致sql长度超出。如何解决这个问题呢?这时候就可以对这个list进行分段处理,一段一段的去查询。
二、List分段的实现方式
/**
* 模拟通过id获取的数据
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IdData {
private Integer id;
private Integer price;
}
模拟我们通过id去查询数据后的返回对象。
(一)、使用List的subList方法
public class ListSectionTest {
private final static List<Integer> idList = new ArrayList<>();
static {
idList.add(1);
idList.add(2);
idList.add(3);
idList.add(4);
idList.add(5);
idList.add(6);
idList.add(7);
idList.add(8);
idList.add(9);
idList.add(10);
}
public static void main(String[] args) {
List<List<Integer>> idPartition = subSection(idList, 2);
List<IdData> dataList = new ArrayList<>();
idPartition.forEach(partition -> dataList.addAll(imitateQueryById(partition)));
System.out.println(dataList);
}
public static List<IdData> imitateQueryById(List<Integer> list) {
return list.stream().map(it -> IdData.builder().id(it).price((int) (Math.random() * 10)).build()).collect(Collectors.toList());
}
public static <T> List<List<T>> subSection(List<T> list, Integer partSize) {
int length = list.size();
//加partSize-1,相当于加不满一组。
int groupNum = (length + partSize - 1) / partSize;
List<List<T>> result = new ArrayList<>(groupNum);
for (int i = 0; i < groupNum; i++) {
int fromIndex = i * partSize;
int endIndex = Math.min((i + 1) * partSize, length);
result.add(list.subList(fromIndex, endIndex));
}
return result;
}
}
可以看到,我们通过subSection把List分成了5个片段,或者说5组。然后每组再去获取数据。我们是通过List的subList方法进行实现的,通过计算idList可以被分成几个组,算出每个组的开始位置和结束位置,最后获得分组结果。imitateQueryById方法是模拟我们通过id查询数据库的数据。
(二)、引入第三方工具类
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
引入jar包
public static void main(String[] args) {
// List<List<Integer>> idPartition = subSection(idList, 2);
List<List<Integer>> idPartition = Lists.partition(idList, 2);
List<IdData> dataList = new ArrayList<>();
idPartition.forEach(partition -> {
System.out.println(partition);
dataList.addAll(imitateQueryById(partition));
});
System.out.println(dataList);
}
使用第三方工具的Lists.partition方法进行分组,省去了我们自定义分组方法的过程。
三、总结
List<List<Integer>>有点像二维数组,但是比二维数组更加的灵活,因为嵌套的第二个List的长度是可以变化的。