詳解Java中兩種分頁遍歷的使用姿勢
在日常開發(fā)中,分頁遍歷迭代的場景可以說非常普遍了,比如掃表,每次撈100條數(shù)據(jù),然后遍歷這100條數(shù)據(jù),依次執(zhí)行某個業(yè)務邏輯;這100條執(zhí)行完畢之后,再加載下一百條數(shù)據(jù),直到掃描完畢
那么要實現(xiàn)上面這種分頁迭代遍歷的場景,我們可以怎么做呢
本文將介紹兩種使用姿勢
- 常規(guī)的使用方法
- 借助Iterator的使用姿勢
1. 數(shù)據(jù)查詢模擬
首先mock一個分頁獲取數(shù)據(jù)的邏輯,直接隨機生成數(shù)據(jù),并且控制最多返回三頁
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. 基本實現(xiàn)方式
針對這種場景,最常見也是最簡單直觀的實現(xiàn)方式
- while死循環(huán)
- 內部遍歷
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. 迭代器實現(xiàn)方式
接下來介紹一種更有意思的方式,借助迭代器的遍歷特性來實現(xiàn),首先自定義一個通用分頁迭代器
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;
}
// 當前的數(shù)據(jù)已經加載完畢,嘗試加載下一批
if (!hasMore) {
return false;
}
list = load(start, size);
if (list == null || list.isEmpty()) {
// 沒有加載到數(shù)據(jù),結束
return false;
}
if (list.size() < size) {
// 返回條數(shù)小于限制條數(shù),表示還有更多的數(shù)據(jù)可以加載
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);
}
接下來借助上面的迭代器可以比較簡單的實現(xiàn)我們的需求了
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);
}
}
那么問題來了,上面這種使用方式比前面的優(yōu)勢體現(xiàn)再哪兒呢?
雙層循環(huán)改為單層循環(huán)
接下來接入重點了,在jdk1.8引入了函數(shù)方法 + lambda之后,又提供了一個更簡潔的使用姿勢
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;
}
// 當前的數(shù)據(jù)已經加載完畢,嘗試加載下一批
if (!hasMore) {
return false;
}
list = loadFunc.load(start, size);
if (list == null || list.isEmpty()) {
// 沒有加載到數(shù)據(jù),結束
return false;
}
if (list.size() < size) {
// 返回條數(shù)小于限制條數(shù),表示還有更多的數(shù)據(jù)可以加載
hasMore = false;
}
currentIndex = 0;
start += list.size();
return true;
}
@Override
public T next() {
return list.get(currentIndex++);
}
}
}
在jdk1.8及之后的使用姿勢,一行代碼即可
private static void scanByIteratorInJdk8() {
new MyIterator<>(IteratorTestForJdk18::randStr)
.forEachRemaining(System.out::println);
}
這次對比效果是不是非常顯眼了,從此以后分頁迭代遍歷再也不用冗長的雙重迭代了
到此這篇關于詳解Java中兩種分頁遍歷的使用姿勢的文章就介紹到這了,更多相關Java 分頁遍歷內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
為什么說要慎用SpringBoot @ComponentScan
本文主要介紹了為什么說要慎用SpringBoot @ComponentScan,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧2021-07-07
Java多線程通訊之wait,notify的區(qū)別詳解
這篇文章主要介紹了Java多線程通訊之wait,notify的區(qū)別詳解,非常不錯,具有一定的參考借鑒借鑒價值,需要的朋友可以參考下2018-07-07
Java 獲取當前時間及實現(xiàn)時間倒計時功能【推薦】
這篇文章主要介紹了Java 獲取當前時間及實現(xiàn)時間倒計時功能 ,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-05-05
常用校驗注解之@NotNull,@NotBlank,@NotEmpty的區(qū)別及說明
這篇文章主要介紹了常用校驗注解之@NotNull,@NotBlank,@NotEmpty的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01

