스택 추적이란 무엇이며 어떻게 추적 오류를 사용하여 응용 프로그램 오류를 디버깅 할 수 있습니까?


644

때로는 응용 프로그램을 실행할 때 다음과 같은 오류가 발생합니다.

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

사람들은 이것을 "스택 추적"이라고합니다. 스택 추적이란 무엇입니까? 내 프로그램에서 발생하는 오류에 대해 무엇을 알 수 있습니까?


이 질문에 대해-초보자 프로그래머가 "오류를 얻는"곳에서 질문이 나오고 스택 추적이 무엇인지 또는 어떻게 사용할 수 있는지 이해하지 않고 스택 추적과 임의의 코드 블록을 붙여 넣습니다. 이 질문은 스택 추적의 가치를 이해하는 데 도움이 필요한 초보자 프로그래머를위한 참고 자료입니다.


25
또한 스택 추적 행에 파일 이름과 행 번호가 포함되어 있지 않으면 해당 행의 클래스가 디버그 정보로 컴파일되지 않은 것입니다.
Thorbjørn Ravn Andersen

답변:


589

간단히 말해서 스택 추적 은 예외가 발생했을 때 응용 프로그램이 수행했던 메서드 호출 목록입니다.

간단한 예

질문에 주어진 예를 통해 응용 프로그램에서 예외가 발생한 위치를 정확하게 결정할 수 있습니다. 스택 추적을 살펴 보자.

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

이것은 매우 간단한 스택 추적입니다. "at ..."목록의 시작 부분에서 시작하면 오류가 발생한 위치를 알 수 있습니다. 우리가 찾고있는 것은 응용 프로그램의 일부인 최상위 메서드 호출입니다. 이 경우 다음과 같습니다.

at com.example.myproject.Book.getTitle(Book.java:16)

이것을 디버깅하기 위해 우리는 Book.javaline을 열어 볼 수 있습니다 16.

15   public String getTitle() {
16      System.out.println(title.toString());
17      return title;
18   }

이것은 아마도 (아마도 title) null위의 코드에 있음을 나타냅니다 .

예외 체인이있는 예

때때로 응용 프로그램은 예외를 잡아서 다른 예외의 원인으로 다시 발생시킵니다. 일반적으로 다음과 같습니다.

34   public void getBookIds(int id) {
35      try {
36         book.getId(id);    // this method it throws a NullPointerException on line 22
37      } catch (NullPointerException e) {
38         throw new IllegalStateException("A book has a null property", e)
39      }
40   }

이것은 다음과 같은 스택 추적을 제공 할 수 있습니다.

Exception in thread "main" java.lang.IllegalStateException: A book has a null property
        at com.example.myproject.Author.getBookIds(Author.java:38)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
        at com.example.myproject.Book.getId(Book.java:22)
        at com.example.myproject.Author.getBookIds(Author.java:36)
        ... 1 more

이것과 다른 점은 "Caused by"입니다. 때로는 예외에 여러 "원인"섹션이 있습니다. 이를 위해 일반적으로 스택 추적에서 가장 낮은 "원인"섹션 중 하나 인 "근본 원인"을 찾습니다. 우리의 경우 :

Caused by: java.lang.NullPointerException <-- root cause
        at com.example.myproject.Book.getId(Book.java:22) <-- important line

다시 말하지만,이 예외와 함께 우리는 라인을보고 싶어 22Book.java가 발생할 수 있습니다 무엇을 참조하십시오 NullPointerException여기.

라이브러리 코드로 더 어려운 예제

일반적으로 스택 추적은 위의 두 예제보다 훨씬 더 복잡합니다. 다음은 예제입니다 (긴 예제이지만 여러 수준의 연결 예외를 보여줍니다).

javax.servlet.ServletException: Something bad happened
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: com.example.myproject.MyProjectServletException
    at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30)
    ... 27 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
    at $Proxy19.save(Unknown Source)
    at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
    at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
    ... 32 more
Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
    at org.hsqldb.jdbc.Util.throwError(Unknown Source)
    at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
    ... 54 more

이 예에는 더 많은 것이 있습니다. 우리가 주로 염려하는 것은 코드 에서 나온 메소드를 찾는 것인데, 이는 com.example.myproject패키지에있는 것입니다. 위의 두 번째 예에서 먼저 근본 원인을 찾아 보려고합니다.

Caused by: java.sql.SQLException

그러나 그 아래의 모든 메소드 호출은 라이브러리 코드입니다. 위의 "Caused by"로 넘어 가서 코드에서 시작된 첫 번째 메소드 호출을 찾으십시오.

at com.example.myproject.MyEntityService.save(MyEntityService.java:59)

이전 예제에서와 같이이 오류가 발생한 곳이기 때문에 MyEntityService.java온라인 에서 살펴 봐야 59합니다 (SQLException은 오류를 나타 내기 때문에 오류가 발생한 것이 약간 분명하지만 디버깅 절차는 우리가 따르는 것입니다).


3
@RobHruska-아주 잘 설명했습니다. +1. 예외 추적을 문자열로 사용하고 스택 추적을 분석하는 유용한 방법을 제공하는 파서를 알고 있습니까? -getLastCausedBy () 또는 getCausedByForMyAppCode ( "com.example.myproject")
Andy Dufresne

1
@AndyDufresne-나는 어떤 것도 보지 못했지만 다시는 실제로 보지 않았습니다.
Rob Hruska

1
제안 된 개선 : Exception in thread "main"첫 번째 예제에서 시작하는 스택 추적의 첫 번째 줄을 설명하십시오 . 이 줄에 종종 변수 값과 같은 문제를 진단하는 데 도움이되는 메시지가 수반된다고 설명하는 것이 도움이 될 것이라고 생각합니다. 직접 수정하려고했지만 이러한 아이디어를 기존 답변 구조에 맞추려고 애 쓰고 있습니다.
코드 견습생

5
또한 Java 1.7에는 "Suppressed :"-이 예외에 대해 "Caused by :"를 표시하기 전에 억제 된 예외 스택 추적을 나열합니다. try-with-resource 구문에 의해 자동으로 사용됩니다 : docs.oracle.com/javase/specs/jls/se8/html/… 리소스 종료 중에 발생 된 예외가 있으면 예외를 포함합니다.
dhblah

JEP openjdk.java.net/jeps/8220715 가 있습니다. 'this.nullInstanceField'가 널이므로 'nullInstanceField'필드를 쓸 수 없습니다.
Mahatma_Fatal_Error

80

이 답변을 게시하여 최상위 답변 (활동별로 정렬 할 때)이 잘못 된 것이 아닙니다.

Stacktrace 란 무엇입니까?

stacktrace는 매우 유용한 디버깅 도구입니다. 포착되지 않은 예외가 발생했을 때 (또는 스택 추적이 수동으로 생성 된 시간) 호출 스택 (즉, 해당 지점까지 호출 된 함수의 스택)을 표시합니다. 이것은 오류가 발생한 위치뿐만 아니라 프로그램이 코드 위치에서 어떻게 종료되었는지를 보여주기 때문에 매우 유용합니다. 이것은 다음 질문으로 이어집니다.

예외 란 무엇입니까?

예외는 런타임 환경에서 오류가 발생했음을 알리기 위해 사용하는 것입니다. 널리 사용되는 예는 NullPointerException, IndexOutOfBoundsException 또는 ArithmeticException입니다. 불가능한 일을하려고 할 때 발생합니다. 예를 들어 Null 객체를 역 참조하려고하면 NullPointerException이 발생합니다.

Object a = null;
a.toString();                 //this line throws a NullPointerException

Object[] b = new Object[5];
System.out.println(b[10]);    //this line throws an IndexOutOfBoundsException,
                              //because b is only 5 elements long
int ia = 5;
int ib = 0;
ia = ia/ib;                   //this line throws an  ArithmeticException with the 
                              //message "/ by 0", because you are trying to
                              //divide by 0, which is not possible.

Stacktrace / Exception을 어떻게 처리해야합니까?

처음에 예외의 원인을 찾으십시오. 예외 이름을 Google로 검색하여 예외의 원인을 찾으십시오. 대부분 잘못된 코드로 인해 발생합니다. 위의 예제에서 모든 예외는 잘못된 코드로 인해 발생합니다. 따라서 NullPointerException 예제의 경우 a해당 시간이 null이 아닌지 확인할 수 있습니다. 예를 들어 a다음과 같은 검사를 초기화 하거나 포함시킬 수 있습니다.

if (a!=null) {
    a.toString();
}

이런 식으로 문제가되는 행은 if가 실행되지 않습니다 a==null. 다른 예제도 마찬가지입니다.

때로는 예외가 발생하지 않았는지 확인할 수 없습니다. 예를 들어, 프로그램에서 네트워크 연결을 사용하는 경우 컴퓨터가 인터넷 연결을 잃는 것을 막을 수 없습니다 (예 : 사용자가 컴퓨터의 네트워크 연결을 끊는 것을 막을 수 없습니다). 이 경우 네트워크 라이브러리에서 예외가 발생합니다. 이제 예외를 잡아서 처리 해야합니다. 즉, 네트워크 연결의 예에서 연결을 다시 열거 나 사용자에게 알리거나 이와 유사한 것을 알려야합니다. 또한 catch를 사용할 때마다 항상 catch하려는 예외 만 포착하고 다음 과 같은 넓은 catch 문을 사용하지 마십시오.catch (Exception e)그것은 모든 예외를 잡을 것입니다. 그렇지 않으면 실수로 잘못된 예외를 포착하여 잘못된 방식으로 대응할 수 있기 때문에 이것은 매우 중요합니다.

try {
    Socket x = new Socket("1.1.1.1", 6789);
    x.getInputStream().read()
} catch (IOException e) {
    System.err.println("Connection could not be established, please try again later!")
}

왜 사용하지 않아야 catch (Exception e)합니까?

작은 예외를 사용하여 모든 예외를 잡아야하는 이유를 보여 드리겠습니다.

int mult(Integer a,Integer b) {
    try {
        int result = a/b
        return result;
    } catch (Exception e) {
        System.err.println("Error: Division by zero!");
        return 0;
    }
}

어떤이 코드가 시도된다 캐치하는 것입니다 ArithmeticException0으로 가능한 부문에 의한 그러나 그것은 또한 가능한 잡는다 NullPointerException경우 발생되는 a또는 b됩니다 null. 이것은 당신이 얻을 수 NullPointerException있지만 그것을 ArithmeticException으로 취급하고 아마도 잘못된 일을 할 것임을 의미합니다. 가장 좋은 경우에는 여전히 NullPointerException이 있다는 것을 그리워합니다. 그런 것들로 인해 디버깅이 훨씬 어려워 지므로 그렇게하지 마십시오.

TLDR

  1. 예외의 원인을 파악하고 수정하여 예외가 전혀 발생하지 않도록하십시오.
  2. 1. 불가능한 경우 특정 예외를 잡아서 처리하십시오.

    • try / catch를 추가 한 다음 예외를 무시하지 마십시오. 하지마!
    • 를 사용하지 말고 catch (Exception e)항상 특정 예외를 잡으십시오. 그것은 당신에게 많은 두통을 저장합니다.

1
버그 마스킹을 피해야하는 이유에 대한 좋은 설명
Sudip Bhandari

2
나는이 답변을 게시하고 있으므로 최상위 답변 (활동별로 정렬 할 때)은 명백한 잘못 이 아니므로 지금까지 변경 된 이후로 당신이 말하는 것에 대해 전혀 모른다. 그러나 받아 들여진 대답은 확실히 더 많은
방해이다

1
내가 아는 한, 내가 의미하는 것은 지금까지 삭제되었습니다. 기본적으로 "단지 try {} catch (Exception e) {}를 넣고 모든 오류를 무시하십시오"라고했습니다. 허용 된 답변은 내 답변보다 훨씬 오래되었으므로 문제에 대해 약간 다른 견해를 제시하려고했습니다. 다른 사람의 답변을 복사하거나 다른 사람들이 이미 잘 다룬 내용을 다루는 데 도움이되지 않는다고 생각합니다.
Dakkaron

"예외를 포착하지 마십시오"라고 말하는 것은 오해의 소지가 있습니다. 단 하나의 유스 케이스입니다. 귀하의 예는 훌륭하지만 스레드 루프의 상단에있는 곳은 어떻습니까? 항상 예외 (또는 Throwable)를 잡아서 보이지 않게 사라지지 않도록 기록해야합니다 (일반적으로 실행에서 발생하는 예외는 스레드 / 로거를 설정하지 않으면 올바르게 기록되지 않습니다).
Bill K

1
멀티 스레딩에만 문제가 있기 때문에이 특별한 경우를 포함하지 않았습니다. 단일 스레딩에서 누출 된 예외는 프로그램을 종료하고 표시됩니다. 누군가 예외를 올바르게 처리하는 방법을 모른다면, 보통 멀티 스레딩을 사용하는 방법을 모른다.
Dakkaron

21

Rob이 언급 한 내용을 추가합니다. 응용 프로그램에서 중단 점을 설정하면 스택을 단계별로 처리 할 수 ​​있습니다. 이를 통해 개발자는 디버거를 사용하여 메서드가 예상치 못한 작업을 수행하는 정확한 지점을 확인할 수 있습니다.

Rob은 NullPointerException(NPE)를 사용하여 일반적인 것을 설명 했으므로 다음과 같은 방식으로이 문제를 제거 할 수 있습니다.

다음과 같은 매개 변수를 취하는 메소드가있는 경우 : void (String firstName)

우리의 코드에서 우리는 firstName값 을 포함하는 것을 평가하고 싶을 것입니다.if(firstName == null || firstName.equals("")) return;

위의 내용 firstName은 안전하지 않은 매개 변수로 사용하지 못하게합니다 . 따라서 처리하기 전에 null 검사를 수행하면 코드가 제대로 실행되도록 할 수 있습니다. 메소드를 사용하여 객체를 사용하는 예제를 확장하기 위해 다음을 볼 수 있습니다.

if(dog == null || dog.firstName == null) return;

위의 방법은 null을 확인하는 올바른 순서이며,이 경우 기본 개체, dog로 시작한 다음 처리하기 전에 모든 것이 유효한지 확인하기 위해 가능성의 트리를 걷기 시작합니다. 주문이 취소되면 NPE가 발생하여 프로그램이 중단 될 수 있습니다.


동의했다. 이 접근법은 인 문에있는 참조 찾을하는 데 사용할 수 nullA는 경우 NullPointerException, 예를 들어, 검토되고있다.
Rob Hruska

16
String을 다룰 때 equals 메소드를 사용하려면 비교의 왼쪽에있는 상수를 다음과 같이 사용하는 것이 좋습니다. 대신 : if (firstName == null || firstName.equals ( "" )) 반환; 나는 항상 사용합니다 : if (( ""). equals (firstName)) 이것은 Nullpointer 예외를 방지합니다
Torres

15

Throwable 제품군은 스택 추적 정보 를 조작수있는 또 하나의 스택 추적 기능을 제공 합니다.

표준 행동 :

package test.stack.trace;

public class SomeClass {

    public void methodA() {
        methodB();
    }

    public void methodB() {
        methodC();
    }

    public void methodC() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

스택 추적 :

Exception in thread "main" java.lang.RuntimeException
    at test.stack.trace.SomeClass.methodC(SomeClass.java:18)
    at test.stack.trace.SomeClass.methodB(SomeClass.java:13)
    at test.stack.trace.SomeClass.methodA(SomeClass.java:9)
    at test.stack.trace.SomeClass.main(SomeClass.java:27)

조작 된 스택 추적 :

package test.stack.trace;

public class SomeClass {

    ...

    public void methodC() {
        RuntimeException e = new RuntimeException();
        e.setStackTrace(new StackTraceElement[]{
                new StackTraceElement("OtherClass", "methodX", "String.java", 99),
                new StackTraceElement("OtherClass", "methodY", "String.java", 55)
        });
        throw e;
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

스택 추적 :

Exception in thread "main" java.lang.RuntimeException
    at OtherClass.methodX(String.java:99)
    at OtherClass.methodY(String.java:55)

2
스레드에 대해 어떻게 생각하는지 모르겠습니다 ... 스레드의 특성으로 인해 새로운 개발자에게 자체 스택 추적을 정의하지 말 것을 권합니다.
PeonProgrammer

15

이름을 이해하려면 : 스택 추적은 가장 예외적 인 예외 (예 : 서비스 계층 예외)에서 가장 깊은 예외 (예 : 데이터베이스 예외)에 이르기까지 예외 목록 (또는 "원인"목록)이라고 할 수 있습니다. 우리가 그것을 '스택'이라고 부르는 이유와 마찬가지로 스택이 FILO (First in Last out)이기 때문에 가장 처음부터 가장 깊은 예외가 발생한 다음 일련의 예외가 발생하여 표면 예외가 마지막이었습니다. 하나는 제 시간에 일어 났지만 우리는 처음에 그것을 봅니다.

키 1 : 여기서 이해해야 할 까다 롭고 중요한 것은 가장 깊은 원인이 "근본 원인"이 아닐 수 있습니다. "불량한 코드"를 작성하면 그 아래 계층보다 더 깊은 예외가 발생할 수 있기 때문입니다. 예를 들어, 잘못된 SQL 쿼리로 인해 syndax 오류 대신 bottem에서 SQLServerException 연결이 재설정 될 수 있으며 이는 스택의 중간에있을 수 있습니다.

-> 중간에 근본 원인을 찾으십시오. 여기에 이미지 설명을 입력하십시오

키 2 : 또 다른 까다 롭지 만 중요한 것은 각 "원인"블록 내부에 있으며, 첫 번째 줄은 가장 깊은 레이어이며이 블록의 첫 번째 장소입니다. 예를 들어

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
           at com.example.myproject.Author.getBookTitles(Author.java:25)
               at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Book.java:16은 Bootstrap.java:14에 의해 호출 된 Auther.java:25에 의해 호출되었으며 Book.java:16이 근본 원인이었습니다. 여기에 시간순으로 트레이스 스택을 정렬하는 다이어그램을 첨부하십시오. 여기에 이미지 설명을 입력하십시오


8

다른 예제에 추가하기 위해 부호 와 함께 나타나는 내부 (중첩) 클래스$있습니다. 예를 들면 다음과 같습니다.

public class Test {

    private static void privateMethod() {
        throw new RuntimeException();
    }

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override public void run() {
                privateMethod();
            }
        };
        runnable.run();
    }
}

이 스택 추적이 발생합니다.

Exception in thread "main" java.lang.RuntimeException
        at Test.privateMethod(Test.java:4)
        at Test.access$000(Test.java:1)
        at Test$1.run(Test.java:10)
        at Test.main(Test.java:13)

5

다른 게시물은 스택 추적이 무엇인지 설명하지만 여전히 작업하기가 어려울 수 있습니다.

스택 추적을 받고 예외의 원인을 추적하려는 경우 Eclipse 에서 Java 스택 추적 콘솔 을 사용하는 것이 좋습니다 . 다른 IDE를 사용하는 경우 비슷한 기능이있을 수 있지만이 답변은 Eclipse에 관한 것입니다.

먼저 Eclipse 프로젝트에서 모든 Java 소스에 액세스 할 수 있는지 확인하십시오.

그런 다음 Java Perspective에서 콘솔 탭 (일반적으로 맨 아래)을 클릭하십시오 . 콘솔보기가 표시되지 않으면 메뉴 옵션 창->보기 표시 로 이동하여 콘솔을 선택하십시오 .

그런 다음 콘솔 창에서 다음 버튼을 클릭하십시오 (오른쪽)

콘솔 버튼

드롭 다운 목록에서 Java 스택 추적 콘솔 을 선택 하십시오.

스택 추적을 콘솔에 붙여 넣습니다. 그런 다음 소스 코드 및 사용 가능한 다른 소스 코드에 대한 링크 목록을 제공합니다.

이것은 당신이 볼 수있는 것입니다 (Eclipse 문서의 이미지).

Eclipse 문서의 다이어그램

가장 최근에 호출 된 메소드 호출은 스택 의 맨 위 입니다 (메시지 텍스트 제외). 스택을 내려 가면 시간이지나갑니다. 두 번째 줄은 첫 번째 줄 등을 호출하는 방법입니다.

오픈 소스 소프트웨어를 사용하는 경우 검사하려는 경우 소스를 다운로드하여 프로젝트에 첨부해야합니다. 프로젝트에서 소스 jar을 다운로드하고 Referenced Libraries 폴더를 열어 공개 소스 모듈 (클래스 파일이있는 모듈)의 jar을 찾은 다음 마우스 오른쪽 단추를 클릭하고 특성을 선택 하고 소스 jar을 첨부하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.