Two usage postures for paging traversal in Java

Paging through iterative scenarios is common in daily development, such as scanning tables, retrieving 100 pieces of data at a time, and then iterating through those 100 pieces of data, executing some business logic in turn. After the 100 pieces are executed, another 100 pieces of data are loaded until the scan is complete

So what can we do to implement the paging iteration scenario above

This article will introduce two kinds of use posture

  • General usage
  • Use Iterator’s gestures

1. Data query simulation

First mock the logic of fetching data in a single page, generate data directly randomly, and control the return of up to three pages

public static int cnt = 0;

private static List<String> randStr(int start, int size) {
    ++cnt;
    if (cnt > 3) {
        return Collections.emptyList();
    } else if (cnt == 3) {
        cnt = 0;
        size -= 2;
    }

    System.out.println("======================= start to gen randList ====================");
    List<String> ans = new ArrayList<>(size);
    for (int i = 0; i < size; i++) {
        ans.add((start + i) + "_" + UUID.randomUUID().toString());
    }
    return ans;
}
Copy the code

2. Basic implementation

For this scenario, the most common and easiest and intuitive implementation

  • The while loop
  • Internal traversal
private static void scanByNormal(a) {
    int start = 0;
    int size = 5;
    while (true) {
        List<String> list = randStr(start, size);
        for (String str : list) {
            System.out.println(str);
        }

        if (list.size() < size) {
            break; } start += list.size(); }}Copy the code

3. Implementation of iterator

A more interesting way to use iterator traversal is to first define a generic page iterator

public static abstract class MyIterator<T> implements Iterator<T> {
    private int start = 0;
    private int size = 5;

    private int currentIndex;
    private boolean hasMore = true;
    private List<T> list;

    public MyIterator(a) {}@Override
    public boolean hasNext(a) {
        if(list ! =null && list.size() > currentIndex) {
            return true;
        }

        // The current data has been loaded, try to load the next batch
        if(! hasMore) {return false;
        }

        list = load(start, size);
        if (list == null || list.isEmpty()) {
            // No data is loaded, end
            return false;
        }

        if (list.size() < size) {
            // The number of returns is less than the limit number, indicating that more data can be loaded
            hasMore = false;
        }

        currentIndex = 0;
        start += list.size();
        return true;
    }

    @Override
    public T next(a) {
        return list.get(currentIndex++);
    }

    public abstract List<T> load(int start, int size);
}
Copy the code

Next, we can implement our requirements with the help of the above iterator

private static void scanByIterator(a) {
    MyIterator<String> iterator = new MyIterator<String>() {
        @Override
        public List<String> load(int start, int size) {
            returnrandStr(start, size); }};while(iterator.hasNext()) { String str = iterator.next(); System.out.println(str); }}Copy the code

So the question comes, what is the advantage of using the above way over the previous one?

  • Double cycle to single cycle

Coming to the point, jdK1.8 introduced the function method + lambda to provide a more concise usage posture

public class IteratorTestForJdk18 {

    @FunctionalInterface
    public interface LoadFunc<T> {
        List<T> load(int start, int size);
    }

    public static class MyIterator<T> implements Iterator<T> {
        private int start = 0;
        private int size = 5;

        private int currentIndex;
        private boolean hasMore = true;
        private List<T> list;
        private LoadFunc<T> loadFunc;

        public MyIterator(LoadFunc<T> loadFunc) {
            this.loadFunc = loadFunc;
        }

        @Override
        public boolean hasNext(a) {
            if(list ! =null && list.size() > currentIndex) {
                return true;
            }

            // The current data has been loaded, try to load the next batch
            if(! hasMore) {return false;
            }

            list = loadFunc.load(start, size);
            if (list == null || list.isEmpty()) {
                // No data is loaded, end
                return false;
            }

            if (list.size() < size) {
                // The number of returns is less than the limit number, indicating that more data can be loaded
                hasMore = false;
            }

            currentIndex = 0;
            start += list.size();
            return true;
        }

        @Override
        public T next(a) {
            returnlist.get(currentIndex++); }}}Copy the code

Using gestures in jdk1.8 and later is a single line of code

private static void scanByIteratorInJdk8(a) {
    new MyIterator<>(IteratorTestForJdk18::randStr)
        .forEachRemaining(System.out::println);
}
Copy the code

This comparison is not very noticeable, from now on paging iteration through no longer long double iteration

II. The other

1. A gray Blog:liuyueyi.github.io/hexblog

A gray personal blog, recording all the study and work in the blog, welcome everyone to go to stroll

2. Statement

As far as the letter is not as good, the above content is purely one’s opinion, due to the limited personal ability, it is inevitable that there are omissions and mistakes, if you find bugs or have better suggestions, welcome criticism and correction, don’t hesitate to appreciate

  • Micro Blog address: Small Gray Blog
  • QQ: a gray /3302797840
  • Wechat official account: One Grey Blog