【Java报错】记录一次调用递归方法导致的 StackOverFlowError 及如何重构递归代码避免栈溢出
1. 遞歸方法
以下代碼為核心代碼,省略了不必要的業(yè)務(wù)流程,用來說明問題:
private boolean getRecommendListAndMatch(String newCycleEndDateStr, String tag) {boolean isMatchSuccess = false;// 獲取數(shù)據(jù)BaseResult recommendList = dataMatchService.getRecommendListByPara();// 數(shù)據(jù)處理assert recommendList != null;if (recommendList.data.total > 0) {// 比較復(fù)雜的業(yè)務(wù)流程isMatchSuccess = true;} else {log.info("結(jié)束時間:{} 內(nèi)無符合條件的數(shù)據(jù)!", newCycleEndDateStr);}// 遞歸調(diào)用方法if (isMatchSuccess) {getRecommendListAndMatch(newCycleEndDateStr, tag);}return isMatchSuccess;}在網(wǎng)上找了幾張圖片:
這是一個很典型的遞歸調(diào)用
棧是一種比較簡單的數(shù)據(jù)結(jié)構(gòu),具有后進先出的特性。
棧本身是一個線性表,但是在這個表中只有一端允許數(shù)據(jù)的進出。那為什么方法要放在棧結(jié)構(gòu)內(nèi)呢?比如方法A調(diào)用方法B,方法A的棧幀要先入棧(A的方法體和參數(shù)都要保存到B方法調(diào)用結(jié)束,否則B方法用的A里的參數(shù)就會出現(xiàn)空指針了)然后入棧B方法的數(shù)據(jù),B方法調(diào)用結(jié)束,B方法的棧幀被彈出,此時如果A方法不再調(diào)用其他方法,A方法執(zhí)行完了之后也會被彈出。
可想而知,如果遞歸方法的參數(shù)、對象較多再加上遞歸層數(shù)較多時,棧的空間畢竟是有限的,溢出就不足為奇了。
2. 重構(gòu)代碼
重構(gòu)遞歸方法的邏輯不復(fù)雜,這里提供一種,使用 do while 實現(xiàn)遞歸邏輯:
// 1. 調(diào)用條件boolean isMatchSuccess;do {// 2. 修改調(diào)用條件isMatchSuccess = getRecommendListAndMatch(newCycleEndDateStr, tag);// 3. 判斷調(diào)用條件是否成立} while (isMatchSuccess);三個點:
- 判斷是否再次調(diào)用的條件
- do方法體里對調(diào)用條件的處理
- while再次判斷調(diào)用條件
主方法的調(diào)整(刪掉遞歸調(diào)用):
private boolean getRecommendListAndMatch(String newCycleEndDateStr, String tag) {boolean isMatchSuccess = false;// 獲取數(shù)據(jù)BaseResult recommendList = dataMatchService.getRecommendListByPara();// 數(shù)據(jù)處理assert recommendList != null;if (recommendList.data.total > 0) {// 比較復(fù)雜的業(yè)務(wù)流程isMatchSuccess = true;} else {log.info("結(jié)束時間:{} 內(nèi)無符合條件的數(shù)據(jù)!", newCycleEndDateStr);}return isMatchSuccess;}重構(gòu)后,每次調(diào)用結(jié)束,方法幀都會從棧內(nèi)彈出,從而避免了長時間過度占用棧空間的問題。
總結(jié)
以上是生活随笔為你收集整理的【Java报错】记录一次调用递归方法导致的 StackOverFlowError 及如何重构递归代码避免栈溢出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【MyBatis使用】mapper.xm
- 下一篇: 【Greenplum代码】记录一次不了解