JavaRush /Java Blog /Random-KO /스택 추적 및 함께 먹는 것
Alukard
레벨 37
London

스택 추적 및 함께 먹는 것

Random-KO 그룹에 게시되었습니다
이 기사에서는 호출 스택 추적이라고도 알려진 Java 현상 StackTrace가 어떻게 작동하는지 배우고 이해합니다. 이 정보는 Java 구문 레벨 9의 시작 부분에서 이 개념을 접한 초보자를 위해 구성되었습니다. 나는 여러분 모두가 Idea , Eclipse 또는 다른 무엇이든 상관없이 IDE에서 작업할 때 비슷한 오류를 한 번 이상 경험했다고 생각합니다.
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작동한다는 사실을 이해해야 합니다 . Стэк이 시점에서 우리는 좀 더 자세히 설명하겠습니다. 스택 컬렉션의 작동 방식 여덟 번째 수준에서는 이미 컬렉션에 대해 알게 되었으며 컬렉션이 Set집합, List목록, Map사전(또는 지도)의 세 그룹으로 나누어져 있다는 것을 알고 있습니다. JavaRush (c) 에 따르면 . 우리는 Stack그룹의 일부입니다 List. 작동 원리는 LIFO ( Last In First Out)로 설명할 수 있습니다. 즉, 이것은 책 더미와 유사한 목록입니다. 먼저 넣은 요소를 가져오려면 Stack나중에 목록에 추가한 모든 요소를 ​​먼저 추출해야 합니다. 위 그림에서 알 수 있듯이, 예를 들어 ArrayList목록에서 인덱스별로 요소를 가져올 수 있는 일반 목록과 다릅니다. 강화를 위해 다시 한 번. 에서 요소를 가져오는 Стэка것은 끝에서만 가능합니다! 추가된 첫 번째 요소는 시작 부분(또는 더 편리한 경우 맨 아래)에 있습니다. Stack 이것은 우리 객체가 가지고 있는 메소드입니다 push(). 스택의 맨 위에 요소를 추가합니다. 객체 pop()- 스택 맨 위에 있는 요소를 반환하고 프로세스에서 제거합니다. 객체 peek()- 스택 맨 위에 있는 요소를 반환하지만 제거하지는 않습니다. int search()- 스택에서 요소를 검색합니다. 발견되면 스택 상단으로부터의 오프셋이 반환됩니다. 그렇지 않으면 -1이 반환됩니다. boolean empty()- 스택이 비어 있는지 확인합니다. 스택이 비어 있으면 true를 반환합니다. 스택에 요소가 포함되어 있으면 false를 반환합니다. 그렇다면 왜 작동 원리에 기초한 시스템이 Java필요한 가요 ? 이렇게 간단한 프로그램을 실행하는 중에 발생한 오류의 예를 아래에서 살펴보겠습니다. StackTraceStack
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하고 이 순간 작업의 현재 값을 숫자 1Стэк 아래에 두는 이름으로 새 메소드를 생성한 다음 메소드 와 프로그램으로 다시 이동합니다. 2 번 아래에 이전에 생성된 위치에 대한 매개 변수를 입력하면 클래스에 있는 눈에 보이지 않는 메서드라고 하며 이는 이미 우리의 요소 번호 3 이 됩니다 . 이 메서드에는 또 다른 내부 호출이 추가됩니다. 오류가 발생하는 null 요소를 확인하려면 4 번 으로 이동하세요 . 프로그램은 오류가 발생할 때까지 전체 전환 체인을 나타내는 오류를 표시해야 합니다. 여기에서 우리 전환 데이터로 이전에 생성된 것이 도움을 받는 곳입니다 . StackTraceconvertStringToIntStackTraceparseIntIntegerStackTraceStackTraceStackTrace
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)
오류가 발생하기 전에는 프로그램이 메소드에 깊이 들어 갔지만 오류가 발생하자마자 모든 것이 역순으로 발생하기 시작합니다. 문제를 설명하는 줄이 인쇄되고(예제에서는 1번), 우리의 값에 추가된 마지막(그리고 맨 위) 값이 가져와서 Стэк4번이 콘솔에 인쇄됩니다(예제에서 2번). 우리는 클래스의 614번째 코드 라인에서 문제가 발생했다는 것을 알 수 있으며 , 이 라인 을 동일한 클래스(예제에서는 3번) Integer메서드의 770번째 라인이라고 불렀습니다 . 이 클래스 메서드는 추가되었을 때 3번이었고, 이 클래스 메서드는 다음과 같습니다. 여전히 우리 눈에 보이지 않는 이 메서드는 프로그램의 10번 라인(예제에서는 4번, 추가할 때는 두 번째)에 있는 메서드에 의해 호출되었으며, 차례로 6번 라인(예제에서는 5번)에서 호출되었습니다. 예 및 추가할 때 각각 첫 번째). 따라서 호출된 메서드를 단계별로 저장함으로써 정확히 오류를 발생시킨 정보의 병렬 인쇄로 다시 돌아갈 수 있었습니다. 그러나 이는 오류가 있는 작업일 뿐만 아니라 응용 프로그램 프로세스에 대한 많은 흥미로운 정보를 얻을 수 있게 해줍니다. 레벨 9의 메인 강의 댓글에 달린 또 다른 인기 있는 예를 살펴보겠습니다. 코드가 있으므로 프로그램 프로세스를 시각화하는 그림을 즉시 첨부하겠습니다. parseIntСтэкIntegerconvertStringToIntmainСтекmainStackTrace
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번째 줄에서 (아직 이 사이클을 연구하지 않은 분들을 위해 이에 대해 읽어 보시기 바랍니다) for라는 수정된 사이클을 시작 forEach하고 어레이에서 콘솔로 데이터를 출력합니다. 즉, 구성을 사용하는 작업 중에 어떤 방법이 실행되었는지에 대한 정보입니다 element.getMethodName(). 보시 다시피 배열의 0 요소는 각각 그 자체로 판명되었습니다 getStackTrace(). 데이터 배열을 수신하는 순간 이것이 실행된 마지막 메서드였기 때문에 맨 위에 올랐으며 Стэка우리의 구성을 기억하고 있습니다. 후입선출 ”은 0 요소 아래 배열에 즉시 추가되는 첫 번째 항목입니다. 다음에서 얻을 수 있는 다른 내용은 다음과 같습니다 StackTraceElement. String getClassName()- 클래스 이름을 반환합니다. 문자열 getMethodName()- 메서드 이름을 반환합니다. 문자열 getFileName()- 파일 이름을 반환합니다(한 파일에 여러 클래스가 있을 수 있음). 문자열 getModuleName()- 모듈 이름을 반환합니다(null일 수 있음). 문자열 getModuleVersion()- 모듈 버전을 반환합니다(null일 수 있음). int getLineNumber()- 메서드가 호출된 파일의 줄 번호를 반환합니다. 이제 일반적인 작동 원리를 이해했으므로 Ide 에서 직접 다양한 방법을 시도해 보시기 바랍니다 . 모든 것을 완전히 익히지 못하더라도 계속 배우면 이 문제에 대한 퍼즐이 나와 같은 방식으로 드러날 것입니다. 나는 당신에게 모든 성공을 기원합니다! Ps. 이 자료가 맘에 드셨다면 좋아요로 응원 부탁드립니다. 당신에게는 어렵지 않습니다. 기쁩니다. 감사합니다. 레벨 41에서 뵙겠습니다 ;)StackTrace
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION