src/java.base/share/classes/java/lang/Throwable.java

Print this page
rev 11099 : 5050783: Added getStackTraceString method to Throwable class

@@ -24,10 +24,11 @@
  */
 
 package java.lang;
 import  java.io.*;
 import  java.util.*;
+import java.util.function.Consumer;
 
 /**
  * The {@code Throwable} class is the superclass of all errors and
  * exceptions in the Java language. Only objects that are instances of this
  * class (or one of its subclasses) are thrown by the Java Virtual Machine or

@@ -638,49 +639,63 @@
      * Prints this throwable and its backtrace to the specified print stream.
      *
      * @param s {@code PrintStream} to use for output
      */
     public void printStackTrace(PrintStream s) {
-        printStackTrace(new WrappedPrintStream(s));
+        printStackTrace(s::println, s);
     }
 
-    private void printStackTrace(PrintStreamOrWriter s) {
+    /**
+     * Returns string representation of this throwable and its backtrace.
+     *
+     * @return string representation of this {@code Throwable} and its backtrace
+     * @since   1.9
+     */
+    public String getStackTraceString() {
+        final StringBuilder sb = new StringBuilder();
+        printStackTrace(line -> sb.append(line).append(System.lineSeparator()), sb);
+
+        return sb.toString();
+    }
+
+    private void printStackTrace(Consumer<String> s, Object lock) {
         // Guard against malicious overrides of Throwable.equals by
         // using a Set with identity equality semantics.
         Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
         dejaVu.add(this);
 
-        synchronized (s.lock()) {
+        synchronized (lock) {
             // Print our stack trace
-            s.println(this);
+            s.accept(toString());
             StackTraceElement[] trace = getOurStackTrace();
             for (StackTraceElement traceElement : trace)
-                s.println("\tat " + traceElement);
+                s.accept("\tat " + traceElement);
 
             // Print suppressed exceptions, if any
             for (Throwable se : getSuppressed())
-                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
+                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu, lock);
 
             // Print cause, if any
             Throwable ourCause = getCause();
             if (ourCause != null)
-                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
+                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu, lock);
         }
     }
 
     /**
      * Print our stack trace as an enclosed exception for the specified
      * stack trace.
      */
-    private void printEnclosedStackTrace(PrintStreamOrWriter s,
+    private void printEnclosedStackTrace(Consumer<String> s,
                                          StackTraceElement[] enclosingTrace,
                                          String caption,
                                          String prefix,
-                                         Set<Throwable> dejaVu) {
-        assert Thread.holdsLock(s.lock());
+                                         Set<Throwable> dejaVu,
+                                         Object lock) {
+        assert Thread.holdsLock(lock);
         if (dejaVu.contains(this)) {
-            s.println("\t[CIRCULAR REFERENCE:" + this + "]");
+            s.accept("\t[CIRCULAR REFERENCE:" + this + "]");
         } else {
             dejaVu.add(this);
             // Compute number of frames in common between this and enclosing trace
             StackTraceElement[] trace = getOurStackTrace();
             int m = trace.length - 1;

@@ -689,25 +704,25 @@
                 m--; n--;
             }
             int framesInCommon = trace.length - 1 - m;
 
             // Print our stack trace
-            s.println(prefix + caption + this);
+            s.accept(prefix + caption + this);
             for (int i = 0; i <= m; i++)
-                s.println(prefix + "\tat " + trace[i]);
+                s.accept(prefix + "\tat " + trace[i]);
             if (framesInCommon != 0)
-                s.println(prefix + "\t... " + framesInCommon + " more");
+                s.accept(prefix + "\t... " + framesInCommon + " more");
 
             // Print suppressed exceptions, if any
             for (Throwable se : getSuppressed())
                 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
-                                           prefix +"\t", dejaVu);
+                                           prefix +"\t", dejaVu, lock);
 
             // Print cause, if any
             Throwable ourCause = getCause();
             if (ourCause != null)
-                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
+                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu, lock);
         }
     }
 
     /**
      * Prints this throwable and its backtrace to the specified

@@ -715,55 +730,11 @@
      *
      * @param s {@code PrintWriter} to use for output
      * @since   1.1
      */
     public void printStackTrace(PrintWriter s) {
-        printStackTrace(new WrappedPrintWriter(s));
-    }
-
-    /**
-     * Wrapper class for PrintStream and PrintWriter to enable a single
-     * implementation of printStackTrace.
-     */
-    private abstract static class PrintStreamOrWriter {
-        /** Returns the object to be locked when using this StreamOrWriter */
-        abstract Object lock();
-
-        /** Prints the specified string as a line on this StreamOrWriter */
-        abstract void println(Object o);
-    }
-
-    private static class WrappedPrintStream extends PrintStreamOrWriter {
-        private final PrintStream printStream;
-
-        WrappedPrintStream(PrintStream printStream) {
-            this.printStream = printStream;
-        }
-
-        Object lock() {
-            return printStream;
-        }
-
-        void println(Object o) {
-            printStream.println(o);
-        }
-    }
-
-    private static class WrappedPrintWriter extends PrintStreamOrWriter {
-        private final PrintWriter printWriter;
-
-        WrappedPrintWriter(PrintWriter printWriter) {
-            this.printWriter = printWriter;
-        }
-
-        Object lock() {
-            return printWriter;
-        }
-
-        void println(Object o) {
-            printWriter.println(o);
-        }
+        printStackTrace(s::println, s);
     }
 
     /**
      * Fills in the execution stack trace. This method records within this
      * {@code Throwable} object information about the current state of