将Throwable.getStackTrace()的结果转换为描述堆栈跟踪的字符串最简单的方法是什么?


当前回答

将堆栈跟踪打印到字符串

import java.io.PrintWriter;
import java.io.StringWriter;

public class StackTraceUtils {
    public static String stackTraceToString(StackTraceElement[] stackTrace) {
        StringWriter sw = new StringWriter();
        printStackTrace(stackTrace, new PrintWriter(sw));
        return sw.toString();
    }
    public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
        for(StackTraceElement stackTraceEl : stackTrace) {
            pw.println(stackTraceEl);
        }
    }
}

当您想要打印当前线程堆栈跟踪而不创建Throwable实例时,这非常有用,但请注意,创建新的Throwable并从中获取堆栈跟踪实际上比调用thread.getStackTrace更快、更便宜。

其他回答

番石榴的丢弃类

如果您有实际的Throwables实例,GoogleGuava提供Throwables.getStackTraceAsString()。

例子:

String s = Throwables.getStackTraceAsString ( myException ) ;

Scala版本

def stackTraceToString(e: Exception): String = {
  import java.io.PrintWriter
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}

对我来说,最干净、最简单的方法是:

import java.util.Arrays;
Arrays.toString(e.getStackTrace());

如果您使用的是Java 8,请尝试

Arrays.stream(e.getStackTrace())
                .map(s->s.toString())
                .collect(Collectors.joining("\n"));

您可以找到Throwable.java提供的getStackTrace()函数的代码:

public StackTraceElement[] getStackTrace() {
    return getOurStackTrace().clone();
}

对于StackTraceElement,它提供如下的toString():

public String toString() {
    return getClassName() + "." + methodName +
        (isNativeMethod() ? "(Native Method)" :
         (fileName != null && lineNumber >= 0 ?
          "(" + fileName + ":" + lineNumber + ")" :
          (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
}

因此,只需使用“\n”连接StackTraceElement。

老问题,但我想补充一个特殊情况,即您不想打印所有堆栈,通过删除一些您实际上不感兴趣的部分,排除某些类或包。

使用SelectivePrintWriter代替PrintWriter:

// This filters out this package and up.
String packageNameToFilter = "org.springframework";

StringWriter sw = new StringWriter();
PrintWriter pw = new SelectivePrintWriter(sw, packageNameToFilter);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); 
System.out.println(sStackTrace);

其中SelectivePrintWriter类由以下给出:

public class SelectivePrintWriter extends PrintWriter {
    private boolean on = true;
    private static final String AT = "\tat";
    private String internal;

    public SelectivePrintWriter(Writer out, String packageOrClassName) {
        super(out);
        internal = "\tat " + packageOrClassName;
    }

    public void println(Object obj) {
        if (obj instanceof String) {
            String txt = (String) obj;
            if (!txt.startsWith(AT)) on = true;
            else if (txt.startsWith(internal)) on = false;
            if (on) super.println(txt);
        } else {
            super.println(obj);
        }
    }
}

请注意,这个类可能很容易被Regex、contains或其他条件过滤掉。还要注意,这取决于可丢弃的实现细节(不太可能改变,但仍然如此)。