最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的StackOverflowError錯(cuò)誤問(wèn)題及解決方法

 更新時(shí)間:2022年07月11日 10:38:35   作者:sofia  
這篇文章主要介紹了Java中的StackOverflowError錯(cuò)誤,在本文中,我們仔細(xì)研究了StackOverflower錯(cuò)誤,包括Java代碼如何導(dǎo)致它,以及我們?nèi)绾卧\斷和修復(fù)它,需要的朋友可以參考下

StackOverflowError簡(jiǎn)介

StackOverflowError可能會(huì)讓Java開(kāi)發(fā)人員感到惱火,因?yàn)樗俏覀兛赡苡龅降淖畛R?jiàn)的運(yùn)行時(shí)錯(cuò)誤之一。 在本文中,我們將通過(guò)查看各種代碼示例以及如何處理它來(lái)了解此錯(cuò)誤是如何發(fā)生的。 Stack Frames和StackOverflowerError的發(fā)生方式 讓我們從基礎(chǔ)開(kāi)始。調(diào)用方法時(shí),將在調(diào)用堆棧上創(chuàng)建新的堆棧幀(stack frame)。該堆??蚣馨徽{(diào)用方法的參數(shù)、其局部變。

StackOverflowError 可能會(huì)讓Java開(kāi)發(fā)人員感到惱火,因?yàn)樗俏覀兛赡苡龅降淖畛R?jiàn)的運(yùn)行時(shí)錯(cuò)誤之一。

在本文中,我們將通過(guò)查看各種代碼示例以及如何處理它來(lái)了解此錯(cuò)誤是如何發(fā)生的。

Stack Frames和StackOverflowerError的發(fā)生方式

讓我們從基礎(chǔ)開(kāi)始。調(diào)用方法時(shí),將在調(diào)用堆棧上創(chuàng)建新的堆棧幀(stack frame)。該堆??蚣馨徽{(diào)用方法的參數(shù)、其局部變量和方法的返回地址,即在被調(diào)用方法返回后應(yīng)繼續(xù)執(zhí)行方法的點(diǎn)。

堆棧幀的創(chuàng)建將繼續(xù),直到到達(dá)嵌套方法中的方法調(diào)用結(jié)束。

在此過(guò)程中,如果JVM遇到?jīng)]有空間創(chuàng)建新堆棧幀的情況,它將拋出 StackOverflower 錯(cuò)誤。

JVM遇到這種情況的最常見(jiàn)原因是未終止/無(wú)限遞歸——StackOverflowerr的Javadoc描述提到,錯(cuò)誤是由于特定代碼段中的遞歸太深而引發(fā)的。

然而,遞歸并不是導(dǎo)致此錯(cuò)誤的唯一原因。在應(yīng)用程序不斷從方法內(nèi)調(diào)用方法直到堆棧耗盡的情況下,也可能發(fā)生這種情況。這是一種罕見(jiàn)的情況,因?yàn)闆](méi)有開(kāi)發(fā)人員會(huì)故意遵循糟糕的編碼實(shí)踐。另一個(gè)罕見(jiàn)的原因是方法中有大量局部變量。

當(dāng)應(yīng)用程序設(shè)計(jì)為類之間具有循環(huán)關(guān)系時(shí),也可以拋出StackOverflowError。在這種情況下,會(huì)重復(fù)調(diào)用彼此的構(gòu)造函數(shù),從而引發(fā)此錯(cuò)誤。這也可以被視為遞歸的一種形式。

另一個(gè)引起此錯(cuò)誤的有趣場(chǎng)景是,如果一個(gè)類在同一個(gè)類中作為該類的實(shí)例變量實(shí)例化。這將導(dǎo)致一次又一次(遞歸)調(diào)用同一類的構(gòu)造函數(shù),最終導(dǎo)致堆棧溢出錯(cuò)誤。

StackOverflowerError正在運(yùn)行

在下面所示的示例中,由于意外遞歸,開(kāi)發(fā)人員忘記為遞歸行為指定終止條件,將拋出StackOverflowError錯(cuò)誤:

public class UnintendedInfiniteRecursion {
    public int calculateFactorial(int number) {
        return number * calculateFactorial(number - 1);
    }
}

在這里,對(duì)于傳遞到方法中的任何值,在任何情況下都會(huì)引發(fā)錯(cuò)誤:

public class UnintendedInfiniteRecursionManualTest {
    @Test(expected = <a  rel="external nofollow"  rel="external nofollow"      title="查看更多關(guān)于 StackOverflowError 的文章" target="_blank">StackOverflowError</a>.class)
    public void givenPositiveIntNoOne_whenCalFact_thenThrowsException() {
        int numToCalcFactorial= 1;
        UnintendedInfiniteRecursion uir 
          = new UnintendedInfiniteRecursion();
        
        uir.calculateFactorial(numToCalcFactorial);
    }
    
    @Test(expected = StackOverflowError.class)
    public void givenPositiveIntGtOne_whenCalcFact_thenThrowsException() {
        int numToCalcFactorial= 2;
        UnintendedInfiniteRecursion uir 
          = new UnintendedInfiniteRecursion();
        
        uir.calculateFactorial(numToCalcFactorial);
    }
    
    @Test(expected = StackOverflowError.class)
    public void givenNegativeInt_whenCalcFact_thenThrowsException() {
        int numToCalcFactorial= -1;
        UnintendedInfiniteRecursion uir 
          = new UnintendedInfiniteRecursion();
        
        uir.calculateFactorial(numToCalcFactorial);
    }
}

但是,在下一個(gè)示例中,指定了終止條件,但如果將值 -1 傳遞給 calculateFactorial() 方法,則永遠(yuǎn)不會(huì)滿足終止條件,這會(huì)導(dǎo)致未終止/無(wú)限遞歸:

public class InfiniteRecursionWithTerminationCondition {
    public int calculateFactorial(int number) {
       return number == 1 ? 1 : number * calculateFactorial(number - 1);
    }
}

這組測(cè)試演示了此場(chǎng)景:

public class InfiniteRecursionWithTerminationConditionManualTest {
    @Test
    public void givenPositiveIntNoOne_whenCalcFact_thenCorrectlyCalc() {
        int numToCalcFactorial = 1;
        InfiniteRecursionWithTerminationCondition irtc 
          = new InfiniteRecursionWithTerminationCondition();

        assertEquals(1, irtc.calculateFactorial(numToCalcFactorial));
    }

    @Test
    public void givenPositiveIntGtOne_whenCalcFact_thenCorrectlyCalc() {
        int numToCalcFactorial = 5;
        InfiniteRecursionWithTerminationCondition irtc 
          = new InfiniteRecursionWithTerminationCondition();

        assertEquals(120, irtc.calculateFactorial(numToCalcFactorial));
    }

    @Test(expected = StackOverflowError.class)
    public void givenNegativeInt_whenCalcFact_thenThrowsException() {
        int numToCalcFactorial = -1;
        InfiniteRecursionWithTerminationCondition irtc 
          = new InfiniteRecursionWithTerminationCondition();

        irtc.calculateFactorial(numToCalcFactorial);
    }
}

在這種特殊情況下,如果將終止條件簡(jiǎn)單地表示為:

public class RecursionWithCorrectTerminationCondition {
    public int calculateFactorial(int number) {
        return number <= 1 ? 1 : number * calculateFactorial(number - 1);
    }
}

下面的測(cè)試在實(shí)踐中顯示了這種情況:

public class RecursionWithCorrectTerminationConditionManualTest {
    @Test
    public void givenNegativeInt_whenCalcFact_thenCorrectlyCalc() {
        int numToCalcFactorial = -1;
        RecursionWithCorrectTerminationCondition rctc 
          = new RecursionWithCorrectTerminationCondition();

        assertEquals(1, rctc.calculateFactorial(numToCalcFactorial));
    }
}

現(xiàn)在讓我們來(lái)看一個(gè)場(chǎng)景,其中StackOverflowError錯(cuò)誤是由于類之間的循環(huán)關(guān)系而發(fā)生的。讓我們考慮 ClassOne 和 ClassTwo ,它們?cè)谄錁?gòu)造函數(shù)中相互實(shí)例化,從而產(chǎn)生循環(huán)關(guān)系:

public class ClassOne {
    private int oneValue;
    private ClassTwo clsTwoInstance = null;
    
    public ClassOne() {
        oneValue = 0;
        clsTwoInstance = new ClassTwo();
    }
    
    public ClassOne(int oneValue, ClassTwo clsTwoInstance) {
        this.oneValue = oneValue;
        this.clsTwoInstance = clsTwoInstance;
    }
}
public class ClassTwo {
    private int twoValue;
    private ClassOne clsOneInstance = null;
    
    public ClassTwo() {
        twoValue = 10;
        clsOneInstance = new ClassOne();
    }
    
    public ClassTwo(int twoValue, ClassOne clsOneInstance) {
        this.twoValue = twoValue;
        this.clsOneInstance = clsOneInstance;
    }
}

現(xiàn)在讓我們假設(shè)我們嘗試實(shí)例化ClassOne,如本測(cè)試中所示:

public class CyclicDependancyManualTest {
    @Test(expected = StackOverflowError.class)
    public void whenInstanciatingClassOne_thenThrowsException() {
        ClassOne obj = new ClassOne();
    }
}

這最終導(dǎo)致了StackOverflowError錯(cuò)誤,因?yàn)?nbsp;ClassOne 的構(gòu)造函數(shù)實(shí)例化了 ClassTwo ,而 ClassTwo 的構(gòu)造函數(shù)再次實(shí)例化了 ClassOne 。這種情況反復(fù)發(fā)生,直到它溢出堆棧。

接下來(lái),我們將看看當(dāng)一個(gè)類作為該類的實(shí)例變量在同一個(gè)類中實(shí)例化時(shí)會(huì)發(fā)生什么。

如下一個(gè)示例所示, AccountHolder 將自身實(shí)例化為實(shí)例變量 JointaCountHolder :

public class AccountHolder {
    private String firstName;
    private String lastName;
    
    AccountHolder jointAccountHolder = new AccountHolder();
}

當(dāng) AccountHolder 類實(shí)例化時(shí),由于構(gòu)造函數(shù)的遞歸調(diào)用,會(huì)引發(fā)StackOverflowError錯(cuò)誤,如本測(cè)試中所示:

public class AccountHolderManualTest {
    @Test(expected = StackOverflowError.class)
    public void whenInstanciatingAccountHolder_thenThrowsException() {
        AccountHolder holder = new AccountHolder();
    }
}

解決StackOverflowError

當(dāng)遇到StackOverflowError堆棧溢出錯(cuò)誤時(shí),最好的做法是仔細(xì)檢查堆棧跟蹤,以識(shí)別行號(hào)的重復(fù)模式。這將使我們能夠定位具有問(wèn)題遞歸的代碼。

讓我們研究一下由我們前面看到的代碼示例引起的幾個(gè)堆棧跟蹤。

如果忽略預(yù)期的異常聲明,則此堆棧跟蹤由 InfiniteCursionWithTerminationConditionManualTest 生成:

java.lang.StackOverflowError
 at c.b.s.InfiniteRecursionWithTerminationCondition
  .calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
 at c.b.s.InfiniteRecursionWithTerminationCondition
  .calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
 at c.b.s.InfiniteRecursionWithTerminationCondition
  .calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)
 at c.b.s.InfiniteRecursionWithTerminationCondition
  .calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)

在這里,可以看到第5行重復(fù)。這就是進(jìn)行遞歸調(diào)用的地方?,F(xiàn)在只需要檢查代碼,看看遞歸是否以正確的方式完成。

下面是我們通過(guò)執(zhí)行 CyclicDependancyManualTest (同樣,沒(méi)有預(yù)期的異常)獲得的堆棧跟蹤:

java.lang.StackOverflowError
  at c.b.s.ClassTwo.<init>(ClassTwo.java:9)
  at c.b.s.ClassOne.<init>(ClassOne.java:9)
  at c.b.s.ClassTwo.<init>(ClassTwo.java:9)
  at c.b.s.ClassOne.<init>(ClassOne.java:9)

該堆棧跟蹤顯示了在循環(huán)關(guān)系中的兩個(gè)類中導(dǎo)致問(wèn)題的行號(hào)。ClassTwo的第9行和ClassOne的第9行指向構(gòu)造函數(shù)中試圖實(shí)例化另一個(gè)類的位置。

徹底檢查代碼后,如果以下任何一項(xiàng)(或任何其他代碼邏輯錯(cuò)誤)都不是錯(cuò)誤的原因:

  • 錯(cuò)誤實(shí)現(xiàn)的遞歸(即沒(méi)有終止條件)
  • 類之間的循環(huán)依賴關(guān)系
  • 在同一個(gè)類中實(shí)例化一個(gè)類作為該類的實(shí)例變量

嘗試增加堆棧大小是個(gè)好主意。根據(jù)安裝的JVM,默認(rèn)堆棧大小可能會(huì)有所不同。

-Xss 標(biāo)志可以用于從項(xiàng)目的配置或命令行增加堆棧的大小。

結(jié)論

在本文中,我們仔細(xì)研究了StackOverflower錯(cuò)誤,包括Java代碼如何導(dǎo)致它,以及我們?nèi)绾卧\斷和修復(fù)它。

與本文相關(guān)的源代碼可以在GitHub上找到: https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-exceptions

到此這篇關(guān)于Java中的StackOverflowError錯(cuò)誤的文章就介紹到這了,更多相關(guān)Java StackOverflowError錯(cuò)誤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java稀疏數(shù)組的應(yīng)用實(shí)踐

    Java稀疏數(shù)組的應(yīng)用實(shí)踐

    本文主要介紹了Java稀疏數(shù)組的應(yīng)用實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Spring整合Mybatis詳細(xì)步驟

    Spring整合Mybatis詳細(xì)步驟

    今天帶大家來(lái)學(xué)習(xí)Spring怎么整合Mybatis,文中有非常詳細(xì)的代碼示例及介紹,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • Spring 重定向(Redirect)指南及相關(guān)策略問(wèn)題

    Spring 重定向(Redirect)指南及相關(guān)策略問(wèn)題

    本文介紹了在Spring中實(shí)現(xiàn)重定向的三種不同方法,在執(zhí)行這些重定向時(shí)如何處理/傳遞屬性以及如何處理HTTP POST請(qǐng)求的重定向。關(guān)于Spring 重定向(Redirect)指南的相關(guān)知識(shí)大家參考下本文
    2017-11-11
  • Java中的Caffeine加載與驅(qū)逐策略詳解

    Java中的Caffeine加載與驅(qū)逐策略詳解

    這篇文章主要介紹了Java中的Caffeine加載與驅(qū)逐策略詳解,Caffeine是基于Java 8的高性能緩存庫(kù),可提供接近最佳的命中率,Caffeine與ConcurrentMap相應(yīng),但是不完全相同,本文主要介紹Caffeine,需要的朋友可以參考下
    2023-10-10
  • java實(shí)體類轉(zhuǎn)成map的實(shí)現(xiàn)

    java實(shí)體類轉(zhuǎn)成map的實(shí)現(xiàn)

    這篇文章主要介紹了java實(shí)體類轉(zhuǎn)成map的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Springboot Thymeleaf實(shí)現(xiàn)HTML屬性設(shè)置

    Springboot Thymeleaf實(shí)現(xiàn)HTML屬性設(shè)置

    這篇文章主要介紹了Springboot Thymeleaf實(shí)現(xiàn)HTML屬性設(shè)置,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2007-11-11
  • JDK15正式發(fā)布(新增功能預(yù)覽)

    JDK15正式發(fā)布(新增功能預(yù)覽)

    這篇文章主要介紹了JDK15正式發(fā)布,新增功能預(yù)覽,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • springboot?jpa?實(shí)現(xiàn)返回結(jié)果自定義查詢

    springboot?jpa?實(shí)現(xiàn)返回結(jié)果自定義查詢

    這篇文章主要介紹了springboot?jpa?實(shí)現(xiàn)返回結(jié)果自定義查詢方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • JAVA實(shí)現(xiàn)KMP算法理論和示例代碼

    JAVA實(shí)現(xiàn)KMP算法理論和示例代碼

    本文從理論到代碼講解了JAVA對(duì)KMP算法的實(shí)現(xiàn),大家可以參考一下
    2013-11-11
  • 通過(guò)java反射機(jī)制動(dòng)態(tài)調(diào)用某方法的總結(jié)(推薦)

    通過(guò)java反射機(jī)制動(dòng)態(tài)調(diào)用某方法的總結(jié)(推薦)

    下面小編就為大家?guī)?lái)一篇通過(guò)java反射機(jī)制動(dòng)態(tài)調(diào)用某方法的總結(jié)(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07

最新評(píng)論

开封市| 长岭县| 昆明市| 玉龙| 乡城县| 黑龙江省| 曲水县| 芦溪县| 右玉县| 错那县| 武安市| 弥渡县| 延川县| 呼玛县| 嵊泗县| 泉州市| 驻马店市| 萨嘎县| 长治市| 中山市| 惠州市| 泽库县| 新和县| 静宁县| 新绛县| 巧家县| 咸阳市| 句容市| 汾西县| 大冶市| 灵石县| 增城市| 玉龙| 江陵县| 丹东市| 宝鸡市| 唐海县| 六安市| 仪陇县| 赣榆县| 永吉县|