Two usage postures of page traversal in Java
In daily development, the scenario of paging traversal iteration can be said to be very common. For example, scan the table, retrieve 100 data each time, and then traverse these 100 data to execute a certain business logic in turn; After the execution of these 100 items, load the next 100 items of data until the scanning is completed
So what can we do to realize the above scenario of paging iterative traversal
This article will introduce two kinds of posture
- Conventional usage
- Using the posture of Iterator
1. Data query simulation
First, mock a logic to obtain data by paging, directly generate data randomly, and control to return 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; }
2. Basic implementation mode
For this scenario, the most common and simple and intuitive implementation method
- while loop
- Internal traversal
private static void scanByNormal() { 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(); } }
3. Iterator implementation
Next, we introduce a more interesting way to implement it with the help of the traversal characteristics of iterators. First, customize a general paging 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() { } @Override public boolean hasNext() { 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 loaded, end return false; } if (list.size() < size) { // The number of returned entries is less than the limit, which indicates that more data can be loaded hasMore = false; } currentIndex = 0; start += list.size(); return true; } @Override public T next() { return list.get(currentIndex++); } public abstract List<T> load(int start, int size); }
Next, with the help of the iterator above, we can easily realize our requirements
private static void scanByIterator() { MyIterator<String> iterator = new MyIterator<String>() { @Override public List<String> load(int start, int size) { return randStr(start, size); } }; while (iterator.hasNext()) { String str = iterator.next(); System.out.println(str); } }
So the question is, where are the advantages of the above way of use compared with the previous way?
- Double layer cycle changed to single layer cycle
Next, access the key points in jdk1 8 after introducing function method + lambda, it provides a more concise use 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() { 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 loaded, end return false; } if (list.size() < size) { // The number of returned entries is less than the limit, which indicates that more data can be loaded hasMore = false; } currentIndex = 0; start += list.size(); return true; } @Override public T next() { return list.get(currentIndex++); } } }
In jdk1 8 and later use posture, one line of code is enough
private static void scanByIteratorInJdk8() { new MyIterator<>(IteratorTestForJdk18::randStr) .forEachRemaining(System.out::println); }
Is the contrast effect very conspicuous? From then on, there will be no need for lengthy double iterations
II. other
1. A gray Blog: https://liuyueyi.github.io/hexblog
A gray personal blog, which records all blog posts in study and work. Welcome to visit
2. Declaration
The above contents are only the words of one family. Due to limited personal ability, it is inevitable that there are omissions and mistakes. If you find a bug or have better suggestions, you are welcome to criticize and correct and be grateful
- Microblog address: Small gray Blog
- QQ: Yihui / 3302797840
3. Scan attention
A gray blog