ChatGPT解决这个技术问题 Extra ChatGPT

How can I get the current stack trace in Java?

How do I get the current stack trace in Java, like how in .NET you can do Environment.StackTrace?

I found Thread.dumpStack() but it is not what I want - I want to get the stack trace back, not print it out.

I allways use "new Exception().printStackTrace()" as a watch expression when I'm debugging in Eclipse. That's handy when you suspend at a breakpoint and want to know where you came from.
@TimBüthe: isn't Eclipse already telling you the Stack Trace when you are in debug mode? I think so.
Arrays.toString(Thread.currentThread().getStackTrace()); simple enough.
@Arkanon It refers to java, and is showing how they would do it in .net and what the equivalent is in java.
To print it nicely you can use apache StringUtils: StringUtils.join(currentThread().getStackTrace(), "\n");

D
David Newcomb

You can use Thread.currentThread().getStackTrace().

That returns an array of StackTraceElements that represent the current stack trace of a program.


A cool one-liner if you're already using apache commons to get a string: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
The first element (index 0) in the array is the java.lang.Thread.getStackTrace method, the second (index 1) usually is the first of interest.
A one liner to convert the stack trace to a string that works when you don't have an exception and you aren't using Apache Arrays.toString(Thread.currentThread().getStackTrace())
@Tony 's solution is better because it doesn't require a throwable
As pointed in many answers below - the new Throwable().getStackTrace() is much faster, because it doesn't need to check this != Thread.currentThread() and bypasses potential JVM overheads of calling it through child-class (Exception extends Throwable)
J
JohnK
StackTraceElement[] st = Thread.currentThread().getStackTrace();

is fine if you don't care what the first element of the stack is.

StackTraceElement[] st = new Throwable().getStackTrace();

will have a defined position for your current method, if that matters.


(new Throwable()).getStackTrace() is faster executing too (see bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
Can you explain in more detail how the results of Thread.currentThread().getStackTrace() may be different from new Throwable().getStackTrace() ? I tried both and found that Thread.currentThread().getStackTrace() returns am array with Thread.getStackTrace in index 0 and the calling method is at index 1. The new Throwable().getStackTrace() method returns an array with the calling method at index 0. It seems like both methods have a defined position for the current method but the positions are different. Is there another difference you are pointing out?
@Ryan, there is no guarantee that Thread.currentThread().getStackTrace() does not promise to maintain that position over different versions of the method. So when you happen to check it was at index 1. On some version of the JVM (1.5 or 1.6, don't remember) for Sun, it was index 2. That is what I mean by a defined position - the spec calls for it to be there, and stay there in the future.
@MightyE The bug is now reported as closed as fixed in Java 6. Looking at the internals, it looks like it now does (new Exception()).getStackTrace() when the requested stack trace is on the current thread (which will always be the case for Thread.currentThread().getStackTrace();
@MJustin: the bug is not “now” reported as fixed, it has been fixed even six years before MightyE wrote the comment. In fact, it has been fixed even before Stackoverflow has been founded…
d
dStulle
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}

java has a printStackTrace method defined on Throwable, you can do: new Exception().printStackTrace(System.out) which I can remember, the for loop probably has less overhead, but you should only use this as a debugging thing anyway...
I like this one best because you get a chance to strip out noise, by wrapping your println statement, e.g. for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
j
jjnguy
Thread.currentThread().getStackTrace();

is available since JDK1.5.

For an older version, you can redirect exception.printStackTrace() to a StringWriter() :

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

new Throwable().getStackTrace() is available since JDK1.4…
m
mike rodent

Tony, as a comment to the accepted answer, has given what seems to be the best answer which actually answers the OP's question:

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );

... the OP did NOT ask how to get a String from the stack trace from an Exception. And although I'm a huge fan of Apache Commons, when there is something as simple as the above there is no logical reason to use an outside library.


I have a list of threads and I need to print their stack traces.
In that case, make sure you use Thread.getAllStackTraces() which gives you a Map<Thread, StackTraceElement[]>. Hotspot will safepoint all threads whenever it needs to safepoint one. Zing can bring individual threads to a safepoint without disturbing the other. Getting a stacktrace requires a safepoint. Thread.getAllStackTraces() gets all stack traces and stops all threads only once. Of course, you must find out which mapping you are actually interested in.
s
stikkos

You can use Apache's commons for that:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);

This is a nice one line solution. FYI, for anyone using org.apache.commons.lang3, the full line is: org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
Just to reiterate fileoffset's comment when moving to org.apache.commons.lang3, which I initially overlooked -- the import uses lang3 instead of lang, and replaces getFullStackTrace with getStackTrace.
That is very useful! When debugging using an IDE (for example, IntelliJ IDEA), it is great to use the ExceptionUtils.getStackTrace(new Throwable()) expression to get the stack trace.
V
Vicky Kapadia

On android a far easier way is to use this:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 

Where is getStackTraceString defined? Is this from a third party logging library?
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
k
kukis

Another solution (only 35 31 characters):

new Exception().printStackTrace();   
new Error().printStackTrace();

awesome solution. Now I don't have to loop through all the stack frames
A
Adamski

To get the stack trace of all threads you can either use the jstack utility, JConsole or send a kill -quit signal (on a Posix operating system).

However, if you want to do this programmatically you could try using ThreadMXBean:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos = bean.dumpAllThreads(true, true);

for (ThreadInfo info : infos) {
  StackTraceElement[] elems = info.getStackTrace();
  // Print out elements, etc.
}

As mentioned, if you only want the stack trace of the current thread it's a lot easier - Just use Thread.currentThread().getStackTrace();


The code snippet in this answer comes nearest to programmatically generating the kind of dump you see on sending the JVM the QUIT signal (on Unix like systems) or <ctrl><break> on Windows. Unlike the other answers you get to see monitors and synchronizers as well as just the stack traces (e.g. if you iterate over the StackTraceElement array and do System.err.println(elems[i]) on each). The second line in the snippet is missing bean. before the dumpAllThreads but I guess most people could work that out.
j
jjnguy

Silly me, it's Thread.currentThread().getStackTrace();


C
Christian Ullenboom

In Java 9 there is a new way:

public static void showTrace() {

  List<StackFrame> frames =
    StackWalker.getInstance( Option.RETAIN_CLASS_REFERENCE )
               .walk( stream  -> stream.collect( Collectors.toList() ) );

  for ( StackFrame stackFrame : frames )
    System.out.println( stackFrame );
}

Interesting. :-)
E
Evan Knowles

Getting stacktrace:

StackTraceElement[] ste = Thread.currentThread().getStackTrace();

Printing stacktrace (JAVA 8+):

Arrays.asList(ste).forEach(System.out::println);

Printing stacktrage (JAVA 7):

StringBuilder sb = new StringBuilder();

for (StackTraceElement st : ste) {
    sb.append(st.toString() + System.lineSeparator());
}
System.out.println(sb);

T
Thomas Adkins

I suggest that

  Thread.dumpStack()

is an easier way and has the advantage of not actually constructing an exception or throwable when there may not be a problem at all, and is considerably more to the point.


Okay, actually, the dumpStack() is a static method, and should be accessed in a static way. Thanks, eclipse!
I love the shortcut, but the source code for this method is : new Exception("Stack trace").printStackTrace(); so it's actually building a Throwable
The question was "I found Thread.dumpStack() but it is not what I want - I want to get the stack trace back, not print it out."
Z
Zitrax

To string with guava:

Throwables.getStackTraceAsString(new Throwable())

S
Salvador Valencia

I have a utility method that returns a string with the stacktrace:

static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw, true);
    t.printStackTrace(pw);
    pw.flush();
    sw.flush();
    return sw.toString();
}

And just logit like...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}

This looks like one auto generated by Netbeans.
is logger a built in logger or one that you created and write to a file.
@Doug Hauf, logger is a reference to the built in Java Logger. Make sure you configure the logging.properties file. Add it at the beginning of your class like this: private static final Logger logger = Logger.getLogger( Your_Class_Name.class.getName() );
java.util.logging.Logger#log(Level, String, Throwable) already does this. This is rewriting things that already exist in the Java standard library unnecessarily and is pointing new developers in the wrong direction, which is away from the documentation. By doing this now you have forced the Stacktrace to be formatted a certain way, where as the logging API allows you to vary formatting of the log statement dynamically as you specify it. To my knowledge, log4j also has similar behavior as well. Don't reinvent the wheel because you end up losing things such as I have explained.
It existed in 2012 too. Date doesn't make a difference in your case, unfortunately. See [link](docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log(java.util.logging.Level, java.lang.String, java.lang.Throwable)), [link](docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log(java.util.logging.LogRecord)), etc (there are several functions that pass the Throwable off to the Handlers through to the Formatters in 2012 which was Java7, more than I've listed here. And these functions date back far longer than Java7 has been around; hence J2SE 5.0 javadocs)
b
butterchicken
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

or

Thread.currentThread().getStackTrace()

Won't your top example only give you the stack trace relative to the try/catch block?
what's the differences between the two
P
Peter Mortensen

Maybe you could try this:

catch(Exception e)
{
    StringWriter writer = new StringWriter();
    PrintWriter pw = new PrintWriter(writer);
    e.printStackTrace(pw);
    String errorDetail = writer.toString();
}

The string 'errorDetail' contains the stacktrace.


Z
Zar E Ahmer
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

The last element of the array represents the bottom of the stack, which is the least recent method invocation in the sequence.

A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().

loop through StackTraceElement and get your desired result.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}

Thanks for mentioning the last element contains the most recent. Counter-intuitive and saved me some time.
also .toString() will output all that data nicely into a string
S
Sampath

You can use jstack utility if you want to check the current call stack of your process.

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

佚名

I used answers from above and added formatting

public final class DebugUtil {

    private static final String SEPARATOR = "\n";

    private DebugUtil() {
    }

    public static String formatStackTrace(StackTraceElement[] stackTrace) {
        StringBuilder buffer = new StringBuilder();
        for (StackTraceElement element : stackTrace) {
            buffer.append(element).append(SEPARATOR);
        }
        return buffer.toString();
    }

    public static String formatCurrentStacktrace() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        return formatStackTrace(stackTrace);
    }
}

K
Kubach

For people, who just want to get the current stacktrace to their logs, I would go with:

getLogger().debug("Message", new Throwable());

Cheers


Don't forget that creating new instance of Throwable is a slow operation and will slowdown you code, even you disable debug level on log's. The best approach is validate if debug level is enabled "if (getLogger().isDebugEnabled()) {/*log code*/}. Anyway, the question was "I want to get the stack trace back, not print it out"...
S
SkyWalker

This is an old post, but here is my solution :

Thread.currentThread().dumpStack();

More info and more methods there : http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html


Since Thread.dumpStack() is static, you should just call it directly.
The OP indicated that they want a reference in code to the stack trace, not to print it out.
as @DavidAvendasora mentioned you should call Thread.dumpStack() directly because its static method.
The question was "I found Thread.dumpStack() but it is not what I want - I want to get the stack trace back, not print it out."