Stream分页详解

一、stream分页排序

Stream是Java8中新增的API,用于支持函数式编程。其提供了大量的方法和操作,其中很重要的一种就是排序。在分页操作中,排序也占据着非常重要的地位。

排序可以通过sorted()方法实现。例如:

List list = Arrays.asList(1, 5, 3, 9, 7, 6);
List sortedList = list.stream()
                                 .sorted()
                                 .collect(Collectors.toList());

上述代码中,我们首先将一个整数列表转换成Stream,然后使用sorted()方法对列表进行升序排序,最后通过collect()方法将结果转换为List。

二、stream分为几个区

在进行分页操作时,我们需要将数据分为多个区,以方便进行分页处理。Stream提供了skip()limit()方法可以帮助我们实现这一点。

skip()方法用于跳过前n个元素,返回剩下的元素,代码如下:

List list = Arrays.asList(1, 2, 3, 4, 5, 6);
List result = list.stream()
                            .skip(2)
                            .collect(Collectors.toList());

上述代码中,我们将一个整数列表转换成Stream,然后使用skip()方法跳过前两个元素,返回剩下的四个元素。

limit()方法用于截取Stream的前n个元素,代码如下:

List list = Arrays.asList(1, 2, 3, 4, 5, 6);
List result = list.stream()
                            .limit(3)
                            .collect(Collectors.toList());

上述代码中,我们将一个整数列表转换成Stream,然后使用limit()方法截取前三个元素。

三、stream分页查询

Stream可以帮助我们实现分页操作。以MySQL数据库为例,我们可以通过limit()offset()方法实现分页查询。

假设我们有一个包含1000条记录的用户表,我们想要查询第11到20条记录,代码如下:

int pageNum = 2;    // 第二页
int pageSize = 10;  // 每页10条记录
List userList = userDao.getAllUsers();  // 获取所有用户
List result = userList.stream()
                            .skip((pageNum - 1) * pageSize)
                            .limit(pageSize)
                            .collect(Collectors.toList());

上述代码中,我们先获取了所有的用户记录,并将其转换成Stream。然后使用skip()方法跳过前10条记录(第一页的记录),使用limit()方法截取10条记录,即第11到20条记录。

四、stream分页性能问题

在进行分页操作时,我们需要避免出现性能问题。一般而言,使用limit()skip()方法进行分页操作,并不会影响整个查询的性能。

但是,在对大数据量进行分页查询时(例如上百万条记录),由于Stream是在内存中进行操作的,会导致内存溢出的问题。此时,我们需要考虑使用分页查询的扩展库,例如Mybatis-PageHelper。

五、stream分页1000条数据

在分页中,我们通常会将数据分为若干页。如果我们想要将数据分为1000条一组,则可以使用partition()方法实现,代码如下:

List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
int pageSize = 1000;

List<List> result = IntStream.range(0, (list.size() + pageSize - 1) / pageSize)
                                      .mapToObj(i -> list.subList(i * pageSize, Math.min(pageSize * (i + 1), list.size())))
                                      .collect(Collectors.toList());

上述代码中,我们将一个包含9个元素的整数列表拆分为每1000条一组的集合。使用IntStream.range()方法生成了一系列的数字范围,然后将列表按照指定的大小进行拆分,使用collect()方法将结果转换为List。

六、stream流分页

除了使用limit()skip()方法进行分页操作外,我们还可以使用流分页技术。

在实现流分页时,我们需要自定义一个类,实现Spliterator接口,代码如下:

public class StreamPager implements Spliterator {
    // 分页大小
    private final int pageSize;

    // 数据源
    private final Spliterator source;

    // 当前页数
    private int currentPage = 0;

    // 总页数
    private long totalPages = Long.MAX_VALUE;

    // 当前页记录数
    private int currentPageSize = 0;

    // 当前页数据
    private List currentPageData;

    public StreamPager(Spliterator source, int pageSize) {
        this.pageSize = pageSize;
        this.source = source;
    }

    @Override
    public boolean tryAdvance(Consumer action) {
        if (currentPage == 0) {  // 第一页
            currentPageData = new ArrayList(pageSize);
            while (source.tryAdvance((T t) -> {
                currentPageData.add(t);  // 将记录添加到当前页数据
                currentPageSize++;
            }) && currentPageSize < pageSize) ;
            totalPages = (source.estimateSize() + pageSize - 1) / pageSize;  // 计算总页数
        }

        if (currentPageData.isEmpty()) {  // 没有下一页
            return false;
        }

        action.accept(currentPageData.remove(0));  // 取出记录
        currentPageSize--;
        if (currentPageSize == 0 && currentPage < totalPages) {  // 进入下一页
            currentPage++;
            currentPageSize = 0;
        }

        return true;
    }

    @Override
    public Spliterator trySplit() {
        return null;
    }

    @Override
    public long estimateSize() {
        return totalPages * pageSize;
    }

    @Override
    public int characteristics() {
        return source.characteristics();
    }
}

代码中,我们定义了一个StreamPager类,实现了Spliterator接口。该类用于对数据进行分页操作。

我们可以使用StreamSupport.stream()方法创建一个Stream,并将StreamPager作为参数传入。例如:

List userList = userDao.getAllUsers();  // 获取所有用户
Stream userStream = StreamSupport.stream(new StreamPager(userList.spliterator(), 10), false);
List page1 = userStream.collect(Collectors.toList());  // 获取第一页数据

上述代码中,我们首先获取所有的用户记录,并将其转换为Stream。然后使用自定义的StreamPager类进行分页操作,设置分页大小为10。最后通过collect()方法将结果转换为List。

七、list stream分页

除了使用Stream对象进行分页外,我们还可以使用List对象实现分页操作。例如:

List userList = userDao.getAllUsers();  // 获取所有用户
List page1 = userList.subList(0, 10);  // 获取第一页数据

上述代码中,我们首先获取所有的用户记录,然后使用subList()方法将其拆分为前10条记录,得到第一页数据。

八、stream分组

在对数据进行分页前,我们通常需要将其进行分组。Stream提供了groupingBy()方法可以帮助我们实现分组操作。

例如,我们有一份包含学生成绩的列表,并按照班级进行分组,代码如下:

Map<Integer, List> studentMap = studentList.stream()
                                                     .collect(Collectors.groupingBy(Student::getClassId));

上述代码中,我们将学生列表转换成Stream,并使用groupingBy()方法将其按照班级(classId属性)进行分组,最终得到一个Map,其中Key为班级编号,Value为学生列表。

九、stream流分组

与流分页类似,我们可以自定义一个类,实现Spliterator接口,来实现流分组操作。

例如,我们有一份包含学生成绩的列表,并按照班级进行分组,每组最多包含10条记录,代码如下:

public class StreamGrouper implements Spliterator<Map.Entry<K, List>> {
// 分组方法
private static final BiConsumer<Map<Object, List>, Object> GROUPER = (map, item) -> {
K key = (K) ((Object[]) item)[0];
T value = (T) ((Object[]) item)[1];
map.computeIfAbsent(key, k -> new ArrayList()).add(value);
};

private final Spliterator source;
private final Function classifier;
private final int groupSize;
private final Map<Object, List> buffer = new HashMap();
private long totalGroups = Long.MAX_VALUE;
private Long bufferSize;

public StreamGrouper(Spliterator source, Function classifier, int groupSize) {
this.source = source;
this.classifier = classifier;
this.groupSize = groupSize;
}

@Override
public boolean tryAdvance(Consumer<? super Map.Entry<K, List>> action) {
Object[] currentPair = buffer.isEmpty() ? null : buffer.entrySet().iterator().next().getValue().remove(0);
while (currentPair == null) {
if (bufferSize != null && buffer.size() >= bufferSize) {
drainBuffer(action);
return true;
}

if (!source.tryAdvance(item -> GROUPER.accept(buffer, new Object[]{classifier.apply(item), item}))) {
if (!buffer.isEmpty()) {
drainBuffer(action);
return true;
}
return false;
}

currentPair = buffer.isEmpty() ? null : buffer.entrySet().iterator().next().getValue().remove(0);
}

action.accept(new AbstractMap.SimpleImmutableEntry((K) currentPair[0], bufferMerge((K) currentPair[0], currentPair[1])));
return true;
}

private void drainBuffer(Consumer<? super Map.Entry<K, List>> action) {
Map.Entry<Object, List> head = buffer.entrySet().iterator().next();
K key = (K) head.getKey();
action.accept(new AbstractMap.SimpleImmutableEntry(key, bufferMerge(key, head.getValue())));

buffer.remove(key);
}

private List bufferMerge(K key, Object value) {
List bufferGroup = buffer.get(key);
List result = new ArrayList(bufferGroup.size() + 1);
result.add((T) value);
result.addAll((List) bufferGroup);
return result;
}

@Override
public Spliterator<Map.Entry<K, List>> trySplit() {
if (totalGroups <= 1) {
return null;
}

Spliterator prefix = source.trySplit();
if (prefix == null) {
return null;
}

updateTotalGroups();

long halfGroupSize = totalGroups / 2 / groupSize * groupSize;
if (halfGroupSize == 0) {
return null;
}

currentBufferSize = Math.min(bufferSize, totalGroups / (2 * groupSize));
while (bufferSize == null && currentBufferSize > 0) {
Map.Entry<Object, List> head = buffer.entrySet().iterator().next();
if (head.getValue().size() >= currentBufferSize * groupSize) {
break;
}

if (!prefix.tryAdvance(item -> GROUPER.accept(buffer, new Object[]{classifier.apply(item), item}))) {
break;
}

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/282621.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-22 08:05
下一篇 2024-12-22 08:05

相关推荐

  • jQuery Datatable分页中文

    jQuery Datatable是一个非常流行的数据表插件,它可以帮助您快速地在页面上创建搜索、过滤、排序和分页的数据表格。不过,它的默认设置是英文的,今天我们就来探讨如何将jQu…

    编程 2025-04-29
  • 如何使用integratecustomerdata.stream().filter(c->{ if (collectionutil.isnotempty(

    本文将详细介绍如何在Java编程中使用integratecustomerdata.stream().filter(c->{ if (collectionutil.isnote…

    编程 2025-04-28
  • uniapp分页第二次请求用法介绍

    本文将从多个方面对uniapp分页第二次请求进行详细阐述,并给出对应的代码示例。 一、请求参数的构造 在进行分页请求时,需要传递的参数体包含当前页码以及每页显示的数据量。对于第二次…

    编程 2025-04-27
  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25

发表回复

登录后才能评论