如何将List转换为Page并按id字段进行升降序排序
内存场景下List转Page并按指定属性排序的实现方案
现有代码的核心问题
你当前的代码存在两处逻辑错误,最终既无法实现目标排序,也会得到错误的分页结果:
- 排序逻辑完全失效:
PageImpl只是分页结果的载体类,仅负责存储当前页数据、分页参数、总数据量信息,不会自动根据传入Pageable携带的Sort规则对内存列表做排序。即使你在PageRequest中定义了id降序规则,因为没有实际对列表做排序操作,最终数据顺序和原始列表没有区别。(注:Pageable中的Sort参数只有在Spring Data等持久层框架做数据库查询时,才会被解析为SQL层面的排序逻辑,内存手动构建Page的场景不会生效) - 分片参数错误:
List.subList()方法要求传入**起始索引(包含)和结束索引(不包含)**两个参数,你直接把页码值、页大小值传入方法,除了第一页(page=0)的范围碰巧匹配外,其他页码计算出的分片范围完全错误。
正确实现步骤
整体逻辑要调整为:先对全量列表做目标规则排序,再计算分页索引做安全切片,最后封装为Page对象
- 第一步:基于全量列表构建排序后的数据集
根据需要的升序/降序规则,通过Comparator完成内存排序。比如按id降序的实现:// 按id升序时,去掉.reversed()即可 List<ExtendedUserObject> sortedAllList = extendedResult.stream() .sorted(Comparator.comparing(ExtendedUserObject::getId).reversed()) .toList(); - 第二步:基于排序后的全量列表做安全分页切片
计算分页的起止索引,通过边界值判断避免列表索引越界:int total = sortedAllList.size(); // 计算当前页起始索引,最大不超过列表总长度 int startIndex = Math.min(page * pageSize, total); // 计算当前页结束索引,最大不超过列表总长度 int endIndex = Math.min((page + 1) * pageSize, total); List<ExtendedUserObject> pageContent = sortedAllList.subList(startIndex, endIndex); - 第三步:封装PageImpl对象
将分片内容、分页参数、总数据量传入构造方法,得到的Page对象就同时满足分页结构正确、数据顺序符合id排序要求:Pageable pageable = PageRequest.of(page, pageSize, Sort.by("id").descending()); Page<ExtendedUserObject> extendedPageResult = new PageImpl<>(pageContent, pageable, total); extendedUserObjectAndCount.setExtendedUserObjects(extendedPageResult);
实现注意点
- 必须在全量列表排序完成后再做分片,如果先分片再排序,只会对当前页的少量数据排序,无法实现全局的id排序效果
- 如果排序属性存在空值场景,可以在Comparator中增加空值判断规则,避免排序时抛出空指针异常
内容的提问来源于stack exchange,提问作者Emanuele 1st
相关产品推荐
相关产品推荐

