JavaRush /Java Blog /Random-TW /堆疊追蹤以及它與什麼一起吃
Alukard
等級 37
London

堆疊追蹤以及它與什麼一起吃

在 Random-TW 群組發布
在本文中,您將學習並了解 Java 現象 StackTrace(也稱為呼叫堆疊追蹤)的工作原理。此資訊是為在 Java 語法等級 9 開始時遇到此概念的初學者建構的。 我想你們所有人,至少一次,在使用 IDE 時遇到類似的錯誤,無論是IdeaEclipse或其他東西。
Exception in thread "main" java.lang.ArithmeticException
	at com.example.task01.Test.division(Test.java:10)
	at com.example.task01.Test.main(Test.java:6)
正如您可能已經猜到的,這就是我們的追蹤。但不要急於驚慌,現在我們將為您分解這個例子。首先,您需要了解它的工作原理StackTrace正如Стэк其名稱所示。在這一點上,我們將詳細討論一下。 Stack 集合如何運作 在第八級,您已經熟悉了集合並知道它們分為三組Set- 集合、List- 列表、Map- 字典(或映射)。根據 JavaRush (c)。 我們 Stack是該團體的一部分List。其運作原理可以描述為LIFO,即後進先出。也就是說,這是一個類似一疊書的清單;為了取出我們Stack首先放入的元素,我們需要先提取之後再加入清單中的所有元素。如上圖所示,與常規清單不同,ArrayList我們可以透過索引從清單中取得任何元素。 再次進行強化。Стэка只能從最後取得元素!而添加到其中的第一個元素位於開頭(或底部,這樣更方便)。Stack 這些是我們的物件具有的 方法push()- 將元素添加到堆疊頂部。物件pop()- 傳回堆疊頂部的元素,並在此過程中將其刪除。物件peek()- 傳回堆疊頂部的元素,但不刪除它。int search()- 在堆疊上搜尋元素。如果找到,則傳回其距離堆疊頂部的偏移量。否則返回-1。boolean empty()- 檢查堆疊是否為空。如果堆疊為空則傳回 true。如果堆疊包含元素,則傳回 false。那為什麼Java需要StackTrace一個基於操作原理的模型呢Stack?讓我們來看看下面這個簡單程式執行過程中發生的錯誤範例。
public class Test {

    public static void main(String[] args) {
        System.out.println(convertStringToInt(null));
    }

    public static int convertStringToInt(String s) {
        int x = Integer.parseInt(s);
        return x;
    }
}
我們有一個Test有兩種方法的類別。大家都很熟悉mainconvertStringToInt其邏輯就是將從外部(即方法main)接收到的字串轉換為整數類型並傳回int。正如您所看到的,我們故意傳遞參數而不是帶有某個數字的字串null。我們的方法無法正確處理該參數並導致錯誤NumberFormatException。如您所知,程式開始從方法中計算出其工作main,此時它會建立一個新的Стэк方法,並為其命名,StackTrace並將其工作的當前值置於數字1下,然後我們再次轉到該方法convertStringToInt和程式將我們位置的參數輸入到先前StackTrace在編號2parseInt下創建的參數中,然後調用類別中肉眼不可見的方法,這將已經是我們的Integer元素編號3StackTrace,在該方法中將添加另一個內部調用到StackTrace數字4檢查元素是否為null,這將導致錯誤。程式需要顯示我們的錯誤,指示錯誤發生之前的整個轉換鏈。這就是之前用我們的轉換資料創建的那個來幫助她的地方StackTrace
Exception in thread "main" java.lang.NumberFormatException: null
	at java.base/java.lang.Integer.parseInt(Integer.java:614)
	at java.base/java.lang.Integer.parseInt(Integer.java:770)
	at com.example.task01.Test.convertStringToInt(Solution.java:10)
	at com.example.task01.Test.main(Solution.java:6)
在錯誤發生之前,程式會深入研究方法,但是一旦錯誤發生,一切就開始以相反的順序發生。列印描述問題的一行(範例中的 No.1),然後取得新增到我們的最後一個(頂部)值,Стэк它是第四個值並列印到控制台(範例中的 No.2),然後我們看到問題出現在Integer第 614 行程式碼的類別中,並呼叫同一類別方法的第 770 行parseInt(範例中的第 3 行),當新增到該方法時,Стэк該方法是第 3 行,並且該類別方法,Integer對我們來說仍然不可見,它已經被我們convertStringToInt程式第 10 行的方法呼叫了(範例中的第 4 行,新增時是第二個),而它又在第main6 行(第 5 行)上被調用在範例中以及新增時分別為第一個)。因此,透過Стек逐步儲存我們調用的方法,我們能夠返回main並行列印確切導致錯誤的資訊。但這StackTrace不僅可以處理錯誤,還可以讓我們獲得許多有關應用程式流程的有趣資訊。我們來看第9級主講評論中另一個流行的例子。我們有了程式碼,我會立即附上一張圖片,直觀地展示程式的流程:
public class Test {
    public static void main(String[] args) {
        method1();
        method2();
    }
    public static void method1() {
        //не вызывает ничего
    }
    public static void method2() {
        method3();
        method4();
    }
    public static void method3() {
        //не вызывает ничего
    }
    public static void method4() {
        method5();
    }
    public static void method5() {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        for (StackTraceElement element:stackTraceElements) {
            System.out.println(element.getMethodName());
        }
    }
}
堆疊追蹤及其與什麼一起吃 - 2 到這裡,我們的程式就完美地完成了它的工作並結束了。這是我們將在控制台輸出中看到的內容:
getStackTrace
method5
method4
method2
main

Process finished with exit code 0
我們是如何得出這個結論的?第五種方法(從第 20 行開始)發生了什麼?恐怕我能做的最好的就是將用戶Kirill從評論中最受歡迎的解釋(縮寫)添加到講座中。讓我們轉向創建線StackTrace並逐個分析它:
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement[]- 數組類型的指示(在早期階段,您已經了解了像 int[]、String[] 這樣的數組,這裡是相同的)。 stackTraceElements- 陣列的名稱可以是任何名稱,考慮到一般命名規則,這不會影響工作。 Thread.currentThread()- 獲取當前線程的鏈接,在該線程中執行我們想要跟踪的方法(目前這並不重要,您將在 Java Core 任務的第 16 級更詳細地分析線程) getStackTrace()- 我們獲得所有Стэк被調用的方法(這是的常規getter StackTrace)現在讓我們看看創建的數組可能對我們有用。我們知道數組儲存有關已執行方法的資訊。(c) 為此,在第 21 行,我們啟動一個修改後的循環(順便forforEach一句,對於那些還沒有研究過這個循環的人,我建議您閱讀它)並將數據從數組輸出到控制台,即有關在使用構造的工作期間執行了哪些方法的資訊element.getMethodName()請注意,正如我們所看到的,數組的零元素分別是其自身,getStackTrace()因為在接收資料數組時,它是最後一個執行的方法,因此最終位於頂部Стэка,並記住我們的構造“ “後進先出”立即第一個加入到數組中的零元素下。以下是我們還可以得到的內容StackTraceElement: String getClassName()- 傳回類別的名稱。字串getMethodName()- 傳回方法的名稱。字串getFileName()- 傳回檔案名稱(一個檔案中可以有多個類別)。字串getModuleName()- 傳回模組名稱(可以為空)。字串getModuleVersion()- 返回模組版本(可以為空)。int getLineNumber()- 傳回呼叫該方法的檔案中的行號。 現在您已經了解了一般的操作原理,我建議您StackTrace在您的Ide中親自嘗試不同的方法。即使你還沒有完全掌握所有內容,繼續學習,謎題就會像我在這件事上遇到的那樣。祝大家一切順利!Ps 若您喜歡本篇內容,請按讚支持。這對你來說並不困難,我很高興。謝謝,41 級見;)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION