JDK Throwable
Throwable
1. 使用大量数组和List常量: private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0];
2. 使用静态内部类
3. 拥有自身类的成员对象: cause, suppressedExceptions
public class Throwable implements Serializable { // Array & List常量 private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0]; private StackTraceElement[] stackTrace = UNASSIGNED_STACK; private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0]; private static final List<Throwable> SUPPRESSED_SENTINEL = Collections .unmodifiableList(new ArrayList<Throwable>(0)); private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL; private Throwable cause = this; // 静态内部内 private static class SentinelHolder { public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL = new StackTraceElement("", "", null, Integer.MIN_VALUE); // 输出时当stackTrace为空时,即赋予该值 public static final StackTraceElement[] STACK_TRACE_SENTINEL = new StackTraceElement[] { STACK_TRACE_ELEMENT_SENTINEL }; } public final synchronized void addSuppressed(Throwable exception) { if (exception == this) throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception); if (exception == null) throw new NullPointerException(NULL_CAUSE_MESSAGE); if (suppressedExceptions == null) return; if (suppressedExceptions == SUPPRESSED_SENTINEL) // suppressedExceptions等于初始值,即创建list suppressedExceptions = new ArrayList<>(1); suppressedExceptions.add(exception); } public void printStackTrace(PrintWriter s) { printStackTrace(new WrappedPrintWriter(s)); // 使用静态内部类 } private void printStackTrace(PrintStreamOrWriter s) { Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>()); dejaVu.add(this); synchronized (s.lock()) { // Print our stack trace s.println(this); StackTraceElement[] trace = getOurStackTrace(); for (StackTraceElement traceElement : trace) s.println("\tat " + traceElement); for (Throwable se : getSuppressed()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); Throwable ourCause = getCause(); if (ourCause != null) ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu); } } private abstract static class PrintStreamOrWriter { abstract Object lock(); 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 synchronized StackTraceElement[] getOurStackTrace() { if (stackTrace == UNASSIGNED_STACK || (stackTrace == null && backtrace != null){ int depth = getStackTraceDepth(); stackTrace = new StackTraceElement[depth]; for (int i = 0; i < depth; i++) stackTrace[i] = getStackTraceElement(i); } else if (stackTrace == null) { return UNASSIGNED_STACK; } return stackTrace; } private void printEnclosedStackTrace(PrintStreamOrWriter s, StackTraceElement[] enclosingTrace, String caption, String prefix, Set<Throwable> dejaVu) { assert Thread.holdsLock(s.lock()); if (dejaVu.contains(this)) { s.println("\t[CIRCULAR REFERENCE:" + this + "]"); } else { dejaVu.add(this); // Compute number of frames in common between this and enclosing StackTraceElement[] trace = getOurStackTrace(); int m = trace.length - 1; int n = enclosingTrace.length - 1; while (m >= 0 && n >= 0 && trace[m].equals(enclosingTrace[n])) { m--; n--; } int framesInCommon = trace.length - 1 - m; // Print our stack trace s.println(prefix + caption + this); for (int i = 0; i <= m; i++) s.println(prefix + "\tat " + trace[i]); if (framesInCommon != 0) s.println(prefix + "\t... " + framesInCommon + " more"); // Print suppressed exceptions, if any for (Throwable se : getSuppressed()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, prefix + "\t", dejaVu); // Print cause, if any Throwable ourCause = getCause(); if (ourCause != null) ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu); } } public final synchronized Throwable[] getSuppressed() { if (suppressedExceptions == SUPPRESSED_SENTINEL || suppressedExceptions == null) return EMPTY_THROWABLE_ARRAY; else return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); } public synchronized Throwable getCause() { return (cause==this ? null : cause); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix