What is Throwable?
Throwable is a class, not an interface, because it stores state: stack trace, message, cause, suppressed list. An interface cannot store data.
Junior Level
Definition
java.lang.Throwable is the base class for all objects that can be thrown (throw) and caught (catch). Without inheriting from Throwable, an object cannot be used as an exception.
Throwable is a class, not an interface, because it stores state: stack trace, message, cause, suppressed list. An interface cannot store data.
Hierarchy
Throwable
├── Error - fatal JVM errors
│ ├── OutOfMemoryError
│ └── StackOverflowError
└── Exception - application errors
├── RuntimeException (unchecked)
└── Checked Exceptions
Key methods
Throwable t = new Exception("Something went wrong");
t.getMessage(); // "Something went wrong"
t.printStackTrace(); // Prints call stack to System.err
t.getCause(); // Returns the cause (if any)
t.getStackTrace(); // StackTraceElement[] array
When to use
Throwable is rarely used directly. Usually you work with its subclasses:
Exceptionand subclasses - for application errorsErrorand subclasses - for fatal JVM errors (but they are not caught)
Middle Level
When NOT to use catch(Throwable)
Never use catch (Throwable t) in business logic - it will catch OutOfMemoryError and leave the JVM in an unstable state. Exception: global handler at the application boundary.
Internal structure
Throwable contains a hidden field backtrace (type Object), which is filled by the native method fillInStackTrace(). This field holds the native call stack in JVM memory.
When getStackTrace() is called, the native structure is converted to StackTraceElement[] array - this is a lazy optimization.
Constructor with stack trace control
public Throwable(String message,
Throwable cause,
boolean enableSuppression,
boolean writableStackTrace)
Parameters:
enableSuppression- whether to allow suppressed exceptions // Suppressed exceptions - see file ‘What are suppressed exceptions.md’. // Briefly: if one exception was thrown in try and another in close(), // the second is not lost but added to the suppressed list of the first.writableStackTrace- whether to fill the stack trace
Suppressed Exceptions
A mechanism for preserving “lost” exceptions:
try (FileInputStream fis = new FileInputStream("file.txt")) {
fis.read(); // IOException #1
} // close() throws IOException #2
// #1 - main, #2 - suppressed
When logging through Logback/Log4j2, suppressed exceptions are printed with the Suppressed: prefix.
Serialization
When transmitted over a network (RMI, microservices), the native backtrace is lost. The JVM converts it to Java objects, which increases data size.
Senior Level
Disabling stack trace for performance
For signal exceptions (validation), stack trace is not needed:
public class FastException extends RuntimeException {
public FastException(String message) {
super(message, null, true, false); // writableStackTrace = false
}
}
Speeds up creation by tens of times - native stack walk is not executed.
Immutable Exceptions
In high-load systems, static instances are created:
public static final ValidationException INVALID_EMAIL =
new ValidationException("Invalid email", null, true, false);
Advantages: does not create objects on each call, no GC load. Disadvantages: identical stack trace for all cases.
Distributed systems
Transmitting full stack traces is an anti-pattern:
// At the service boundary
try {
service.process();
} catch (Throwable t) {
// Pass only DTO, not the entire stack
return ErrorResponse.of(t.getClass().getSimpleName(), t.getMessage());
}
Saves megabytes of traffic during mass failures.
printStackTrace() - never in production
printStackTrace() writes to System.err, which:
- Is synchronized - thread blocking
- Does not reach log files without redirection
- In Kubernetes, is split into separate lines
Use loggers: log.error("Msg", throwable).
Diagnostics
toString()- only class name and messageprintStackTrace()- entire tree (slow)getStackTrace()- array of elements (for programmatic analysis)- In distributed systems, use
Trace ID / Span IDto link logs between services
Interview Cheat Sheet
Must know:
Throwable- base class for all objects that can bethrowandcatch- Subclasses:
Error(fatal JVM) andException(application errors) - Stores state: stack trace, message, cause, suppressed list
- Key methods:
getMessage(),getCause(),getStackTrace(),printStackTrace() - Contains hidden field
backtrace, filled by nativefillInStackTrace() - Constructor with
writableStackTrace = falsedisables stack walk (speeds up 10-50x) - Suppressed exceptions - preserve exceptions from
close()in try-with-resources printStackTrace()- never in production (writes toSystem.err, synchronized)
Frequent follow-up questions:
- Why is Throwable a class, not an interface? - Stores state (stack trace, cause, suppressed), interfaces don’t store data
- When NOT to use
catch(Throwable)? - In business logic: will catch OutOfMemoryError; acceptable only in a global handler - What are suppressed exceptions? - If try and close() both threw two exceptions, the second is added to the suppressed list of the first
- Why is printStackTrace() bad for production? - Synchronized, doesn’t reach log files, in Kubernetes is split into lines
Red flags (NOT to say):
- “I use Throwable instead of Exception for all errors” - it will catch Error too
- “printStackTrace() is a normal way to log” - use loggers
- “Throwable is not serializable” - it is, but native backtrace is lost
Related topics:
- [[What is at the top of the exception hierarchy]]
- [[What is the difference between Error and Exception]]
- [[What are suppressed exceptions]]
- [[How to properly log exceptions]]
- [[What is exception chaining]]