What is the difference between Error and Exception?
Both classes inherit from Throwable, but they mean fundamentally different problems:
Junior Level
Key Difference
Both classes inherit from Throwable, but they mean fundamentally different problems:
Error - JVM problems (not application), which usually cannot be fixed.
Exception: AssertionError is technically an Error, but arises from application logic. Used for invariant checking, not external failures.
- Not under developer control
- Don’t catch in normal code
- Examples:
OutOfMemoryError,StackOverflowError
Exception - application errors:
- Expected failures that can be handled
- Need to be handled
- Examples:
IOException,SQLException
Don’t catch Error in normal code. Exceptions: global thread handler (setDefaultUncaughtExceptionHandler), graceful shutdown, health-check mechanisms.
Visually
Throwable
├── Error <- JVM is broken
└── Exception <- Application encountered a problem
Examples
// Error - application is powerless
// java.lang.OutOfMemoryError: Java heap space
List<byte[]> memoryHog = new ArrayList<>();
while (true) memoryHog.add(new byte[1024 * 1024]);
// Exception - can be handled
try {
Files.readAllLines(Paths.get("missing.txt"));
} catch (IOException e) {
System.out.println("File not found, using default");
}
Simple rule
- Error - “JVM died” -> let it crash
- Exception - “something went wrong” - handle or log
Middle Level
OutOfMemoryError - subtypes
OutOfMemoryError comes in different forms:
Java heap space- heap is fullMetaspace- no memory for metadata (often when generating classes via CGLIB)Unable to create new native thread- OS denied creating new threads
Even if you catch OOM, the JVM may be in an unstable state.
NoClassDefFoundError vs ClassNotFoundException
This is a classic interview question:
ClassNotFoundException (Exception):
- You explicitly ask to load a class:
Class.forName("com.mysql.Driver") - Class is not in classpath
- Can be handled
NoClassDefFoundError (Error):
- Class was present at compile time but missing at runtime
- Or its loading failed due to an error in a static block
- Critical environment failure
// If in a class’s static block: // static { int x = 1/0; } // On first load: ExceptionInInitializerError // On subsequent attempts: NoClassDefFoundError (class was not initialized)
AssertionError
Inherits from Error. Thrown by the assert operator (with -ea flag):
assert x > 0 : "x must be positive"; // AssertionError if x <= 0
Use assert for checking algorithm invariants, not for API input validation - use IllegalArgumentException for that.
StackOverflowError vs OutOfMemoryError
- StackOverflowError - stack exhausted (deep recursion). Fix: increase -Xss or fix recursion
- OutOfMemoryError - heap exhausted (many objects). Fix: increase -Xmx or fix the leak
Senior Level
Handling Error - why it’s bad practice
Even if you caught an Error, the JVM may be in an unstable state. The next operation (even logging) may cause a new Error.
Fail Fast & Die Pattern
In Highload systems, on Error the application should terminate quickly:
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler((thread, e) -> {
if (e instanceof Error) {
log.error("Fatal error in thread {}", thread.getName(), e);
System.exit(1); // Die so orchestrator can restart
}
});
}
Kubernetes or another orchestrator will restart a fresh instance.
JVM flag for OOM
-XX:OnOutOfMemoryError="kill -9 %p"
Guarantees process death on OutOfMemoryError.
StackOverflowError
Common Error on infinite recursion. Stack size is limited by -Xss. In deep hierarchies or cycles in Hibernate entities, increasing it may be needed.
// Infinite recursion
public int factorial(int n) {
return n * factorial(n); // StackOverflowError
}
Logging Errors
If you catch Throwable at the top level (main or UncaughtExceptionHandler), do System.exit(1) after logging to not leave the system in a “zombie state”.
Diagnostics
javap -v- see method attributes for exception handling understanding- Thread Dumps -
jstack <pid>shows state of all threads on hang - Heap Dumps -
jmaphelps analyzeOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError- automatic heap dump on OOM
Interview Cheat Sheet
Must know:
Error- JVM problems (cannot fix),Exception- application errors (can handle)- Error:
OutOfMemoryError,StackOverflowError,NoClassDefFoundError- don’t catch - Exception is divided into checked and unchecked (RuntimeException)
NoClassDefFoundError!=ClassNotFoundException: first is Error (was at compile time, missing at runtime), second is Exception (explicitly loaded, not in classpath)AssertionError- technically Error, but from application logic (invariant checking)- Fail Fast & Die: on Error -
System.exit(1), let orchestrator restart - JVM flag
-XX:OnOutOfMemoryError="kill -9 %p"guarantees death on OOM Thread.setDefaultUncaughtExceptionHandler- catches Error at top level
Frequent follow-up questions:
- Can you catch OutOfMemoryError? - Technically yes, but JVM is in unstable state - next operation will fail
- What is the difference between StackOverflowError and OutOfMemoryError? - StackOverflowError - stack exhausted (recursion), OOM - heap exhausted (many objects)
- When is AssertionError an Error, not an Exception? - Because assert checks algorithm invariants, not external failures
- What to do with Error in production? - Log and
System.exit(1), Kubernetes will restart the pod
Red flags (NOT to say):
- “I catch Error and continue working” - JVM is unstable, it’s meaningless
- “NoClassDefFoundError and ClassNotFoundException are the same” - no, first is Error, second is Exception
- “AssertionError is used for input validation” - IllegalArgumentException is for that
Related topics:
- [[What is at the top of the exception hierarchy]]
- [[What is Throwable]]
- [[What is an unchecked exception (Runtime Exception)]]
- [[Is the execution of a finally block guaranteed]]
- [[What is a stack trace]]