0% found this document useful (0 votes)
5 views28 pages

Java Exceptions Interview Prep

This document is a comprehensive guide for Java backend interview preparation focused on exception handling, covering 50 questions across core, intermediate, and advanced levels. It includes explanations of Java's exception hierarchy, the differences between checked and unchecked exceptions, and best practices for exception handling, such as exception chaining and custom exception design. Each question is accompanied by answers, code examples, and interviewer tips to aid candidates in their interview preparation.

Uploaded by

sandeep.r
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views28 pages

Java Exceptions Interview Prep

This document is a comprehensive guide for Java backend interview preparation focused on exception handling, covering 50 questions across core, intermediate, and advanced levels. It includes explanations of Java's exception hierarchy, the differences between checked and unchecked exceptions, and best practices for exception handling, such as exception chaining and custom exception design. Each question is accompanied by answers, code examples, and interviewer tips to aid candidates in their interview preparation.

Uploaded by

sandeep.r
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

☕ Java Backend Interview Prep

Exception Handling
Master Reference for 3-Year Experience Level

50 Questions · Core → Intermediate → Advanced · Code Examples · Tricky Variations

How to Use This Document


Each question card contains: the question itself, a concise answer, code where relevant, and a highlighted interviewer tip.
Difficulty is colour-coded:
• 🟢 Basic — Core JVM/language mechanics every candidate must know cold.
• 🔵 Intermediate — Design decisions, tricky edge cases, method overriding rules.
• 🟣 Advanced — Architectural thinking, Spring philosophy, suppressed exceptions, multi-catch.

Section 1 — Exception Hierarchy & Core Concepts


Questions 1–12 test whether you understand the Java exception family tree and the fundamental mechanics of try-catch-
finally.

Q1 Draw and explain the Java exception hierarchy. [Basic]

Answer:
Java's exception family starts at Throwable, which has two direct subclasses: Error and Exception.
Error: Represents serious JVM problems (OutOfMemoryError, StackOverflowError). You should almost never catch
these.
Exception: The branch you work with. It splits into two categories:
→ Checked exceptions (e.g., IOException, SQLException) — must be declared or caught.
→ Unchecked exceptions extend RuntimeException (e.g., NullPointerException, IllegalArgumentException).

Throwable
├── Error (JVM-level, do NOT catch)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── AssertionError
└── Exception
├── IOException (Checked)

Java Exception Handling Interview Prep · Page


├── SQLException (Checked)
└── RuntimeException (Unchecked)
├── NullPointerException
├── IllegalArgumentException
└── ArrayIndexOutOfBoundsException

💡 Interviewer Tip:
Interviewers expect you to say 'unchecked = extends RuntimeException' without hesitation. They'll also ask:
'Can you catch an Error?' — technically yes, but you almost never should.

Q2 What is the difference between checked and unchecked exceptions? [Basic]

Answer:
Checked exceptions are verified by the compiler. If a method can throw one, you must either catch it or declare it with
'throws'. Examples: IOException, FileNotFoundException.
Unchecked exceptions extend RuntimeException and are not checked at compile time. They typically represent
programming mistakes — null dereferences, bad array indices, illegal arguments.
The key philosophical difference: checked exceptions model recoverable conditions the caller should handle (file not
found, network timeout). Unchecked exceptions model bugs the programmer should fix.

// Checked — compiler forces you to handle it


public void readFile(String path) throws IOException {
[Link]([Link](path));
}

// Unchecked — no compile-time enforcement


public int divide(int a, int b) {
return a / b; // throws ArithmeticException if b == 0
}

💡 Interviewer Tip:
Follow-up: 'Should all exceptions be checked?' This triggers a discussion of the modern Java architectural
debate — Spring uses exclusively unchecked exceptions for a reason.

Q3 What happens in the finally block — when exactly does it NOT execute? [Basic]

Answer:
The finally block runs after try/catch regardless of whether an exception was thrown or caught — with exactly two
exceptions:
1. [Link]() is called — the JVM terminates before finally runs.
2. The JVM crashes or the thread is killed (e.g., via [Link]() or power loss).
Importantly: finally DOES run even if there is a return in the try block. The finally executes, then the return value is sent.

public int test() {


try {

Java Exception Handling Interview Prep · Page


return 1; // Finally still runs!
} finally {
[Link]("finally runs");
// If you put 'return 2' here, it OVERRIDES return 1
}
}
// Prints: 'finally runs', method returns 1

💡 Interviewer Tip:
The classic trap: 'What if finally has a return statement?' Answer: it swallows the try's return value. Interviewers
love this. Also ask: 'What if both catch and finally throw exceptions?' — the finally exception wins.

Q4 Explain try-with-resources. How does it work under the hood? [Basic]

Answer:
Try-with-resources (Java 7+) automatically closes any resource that implements AutoCloseable. The close() method is
called in the finally block by the compiler.
You can declare multiple resources — they close in REVERSE order of declaration.
If both the try body and close() throw exceptions, the try body's exception is propagated and close()'s exception is
added as a suppressed exception (getSuppressed()).

// Syntactic sugar — compiler generates:


try (Connection conn = [Link]();
PreparedStatement ps = [Link](sql)) {
[Link]();
}
// Equivalent to (simplified):
Connection conn = [Link]();
try {
PreparedStatement ps = [Link](sql);
try { [Link](); }
finally { [Link](); } // inner resource closes first
} finally { [Link](); } // outer resource closes last

💡 Interviewer Tip:
Follow-up: 'What are suppressed exceptions?' This leads to [Link]() — a distinguishing
advanced answer.

Q5 What are suppressed exceptions and how do you access them? [Intermediate]

Answer:
When a try-with-resources block closes a resource and BOTH the body AND close() throw exceptions, Java needs to
decide which to propagate.
The primary exception (from the try body) is propagated. The secondary one (from close()) is attached as a 'suppressed'
exception on the primary.
You retrieve them via [Link]() which returns an array of Throwable.

Java Exception Handling Interview Prep · Page


You can also manually add suppressed exceptions with [Link](cause).

try (MyResource r = new MyResource()) {


throw new RuntimeException("primary");
// [Link]() also throws: 'close failed'
} catch (RuntimeException e) {
[Link]([Link]()); // primary
for (Throwable s : [Link]()) {
[Link]([Link]()); // close failed
}
}

💡 Interviewer Tip:
Many candidates know try-with-resources but blank on suppressed exceptions. Mentioning
[Link]() and the fact this was introduced alongside TWR in Java 7 will impress.

Q6 Can we have a try block without catch — only finally? [Basic]

Answer:
Yes. A try block can be followed by just a finally block with no catch at all. This is valid and useful when you want to
ensure cleanup happens but don't want to handle the exception (you let it propagate).
You cannot, however, have a try block with neither catch nor finally — that is a compile error.

// Valid: try + finally, no catch


public void processFile() throws IOException {
InputStream in = new FileInputStream("[Link]");
try {
process(in);
} finally {
[Link](); // always close, even if process() throws
}
}

💡 Interviewer Tip:
Interviewers use this to test if you understand that catch is optional. The natural follow-up: 'Why would you
NOT use try-with-resources here?' Answer: only if you need the resource declared before the try.

Q7 What is exception chaining / wrapping? Why is it important? [Intermediate]

Answer:
Exception chaining means wrapping a low-level exception inside a higher-level, more meaningful one — preserving the
original cause in the chain.
This is critical for debugging: you get both the high-level context (e.g., 'User service failed') and the root cause (e.g.,
'Connection refused') in the stack trace.
Two approaches: pass cause to constructor, or call initCause() (older APIs).

Java Exception Handling Interview Prep · Page


// Wrapping: service layer catches DB exception, rewraps
public User findUser(long id) {
try {
return [Link](id);
} catch (SQLException e) {
// Don't swallow! Wrap and preserve cause
throw new UserServiceException("Failed to fetch user: " + id, e);
}
}

// Older API: initCause()


RuntimeException ex = new RuntimeException("msg");
[Link](originalException);
throw ex;

💡 Interviewer Tip:
A classic anti-pattern to mention: catch (SQLException e) { throw new RuntimeException("error"); } — this
DROPS the cause, making debugging impossible. Never do this.

Q8 What is the difference between throw and throws? [Basic]

Answer:
'throw' is a statement that actually throws an exception object at runtime. It appears inside a method body.
'throws' is a declaration on the method signature that advertises which checked exceptions the method might
propagate. It's a compile-time contract with callers.
You can throw unchecked exceptions without declaring them with 'throws', but it's good practice to still document
them with @throws Javadoc.

// 'throws' in signature = contract with callers


public void connect(String url) throws IOException {
if (url == null) {
throw new IllegalArgumentException("URL must not be null");
// ^ 'throw' is the actual action
}
// ... connection logic that may throw IOException
}

💡 Interviewer Tip:
Simple question but interviewers expect crisp, confident answers. Follow-up: 'Can you throw a checked
exception without declaring it with throws?' — no, the compiler will reject it.

Q9 What happens if an exception is thrown inside a catch block? [Intermediate]

Answer:
If the catch block itself throws an exception, the finally block still runs (if present), and then the new exception
propagates up the call stack.

Java Exception Handling Interview Prep · Page


The original exception is effectively lost unless you explicitly chain it (addSuppressed / cause constructor).
This is why swallowing and re-throwing without chaining is dangerous.

try {
riskyOperation();
} catch (IOException e) {
log(e);
throw new ServiceException("failed", e); // chain e as cause
} finally {
cleanup(); // runs even if catch threw
}

💡 Interviewer Tip:
Interviewers often ask: 'What if both catch and finally throw?' The finally exception wins — the catch's
exception is suppressed/lost (unlike TWR, finally exceptions in plain try blocks are NOT automatically attached
as suppressed).

Q10 Can you catch multiple exceptions in one catch block? How? [Basic]

Answer:
Yes, since Java 7, using the multi-catch syntax with the pipe '|' operator.
The catch parameter is implicitly final in a multi-catch block — you cannot reassign it.
The caught types must not be in an inheritance relationship — catching IOException | FileNotFoundException is a
compile error since FileNotFoundException extends IOException.

// Java 7+ multi-catch
try {
riskyOp();
} catch (IOException | SQLException e) {
// e is effectively final here
[Link]("Operation failed", e);
throw new ServiceException(e);
}

// This is a compile error:


// catch (Exception | IOException e) — inheritance violation

💡 Interviewer Tip:
Multi-catch produces more readable code and avoids duplicated catch bodies. Interviewers expect you to know
the 'effectively final' constraint and the inheritance restriction.

Q11 What is ClassNotFoundException vs NoClassDefFoundError? [Intermediate]

Answer:
ClassNotFoundException (checked exception): Thrown when you try to load a class at runtime via [Link]() or
[Link]() and the class is simply not on the classpath.

Java Exception Handling Interview Prep · Page


NoClassDefFoundError (error): The class WAS available at compile time (it compiled fine), but is missing at runtime. The
JVM found a reference to it in bytecode but cannot locate the actual .class file.
ClassNotFoundException = dynamic loading failure. NoClassDefFoundError = classpath inconsistency at runtime.

// ClassNotFoundException - class never existed at runtime


try {
[Link]("[Link]"); // fails if jar missing
} catch (ClassNotFoundException e) { ... }

// NoClassDefFoundError - compiled fine, missing at runtime


// Imagine [Link] compiled OK but the jar was removed
SomeClass obj = new SomeClass(); // throws NoClassDefFoundError

💡 Interviewer Tip:
This question comes up frequently in senior interviews. The key distinction: one is about dynamic reflection-
based loading (CNFE), the other is about static references in bytecode (NCDFE). One is a checked Exception, the
other is an Error.

What is the difference between Error and Exception? Should you ever catch an Error?
Q12 [Intermediate]

Answer:
Error signals a serious JVM-level problem that applications normally cannot recover from: OutOfMemoryError,
StackOverflowError, VirtualMachineError.
Exception represents conditions an application might reasonably handle.
You SHOULD NOT catch Errors in general because you cannot meaningfully recover. However, there are two legitimate
exceptions:
1. ThreadDeath — sometimes caught in frameworks managing thread lifecycle.
2. OutOfMemoryError — very occasionally caught to log and gracefully shut down (but you can't rely on it having
enough memory to even log).
Catching Throwable (which catches both) is almost always a code smell unless you're writing a top-level framework or
test harness.

💡 Interviewer Tip:
The answer 'you should never catch Error' is too absolute. Show nuance: frameworks like Spring Boot catch
Throwable at top-level handlers to log and return HTTP 500 rather than crashing silently.

Section 2 — Intermediate: Design, Rules & Tricky Mechanics


Questions 13–30 target method overriding rules, custom exception design, propagation, and tricky return-value scenarios.

Java Exception Handling Interview Prep · Page


Q13 What are the method overriding rules for exceptions? [Intermediate]

Answer:
When overriding a method, the overriding method can:
→ Throw fewer checked exceptions than the parent.
→ Throw narrower (subclass) checked exceptions.
→ Throw any unchecked exception regardless of what parent declares.
The overriding method CANNOT throw broader or new checked exceptions not declared in the parent. This preserves
Liskov Substitution Principle — callers coded against the parent interface must not be surprised.

class Parent {
void connect() throws IOException { }
}
class Child extends Parent {
// OK: narrower checked exception
@Override void connect() throws FileNotFoundException { }
}
class Bad extends Parent {
// COMPILE ERROR: SQLException not declared in Parent
@Override void connect() throws SQLException { }
}
class AlsoOk extends Parent {
// OK: unchecked exceptions are always allowed
@Override void connect() throws IllegalStateException { }
}

💡 Interviewer Tip:
A guaranteed interview question at the intermediate level. Interviewers like to ask about interface
implementations — the same rules apply: an implementing class cannot declare broader checked exceptions
than the interface method.

Q14 How do you design a good custom exception? [Intermediate]

Answer:
A well-designed custom exception should:
1. Have a meaningful name that ends in 'Exception' (or 'Error' for severe problems).
2. Provide all four standard constructors: (), (String msg), (String msg, Throwable cause), (Throwable cause).
3. Be unchecked (extend RuntimeException) in most modern applications — checked exceptions add API friction.
4. Include domain-specific fields (error code, resource ID) where useful.
5. Never swallow the cause — always pass it to the super() constructor.

public class OrderNotFoundException extends RuntimeException {


private final long orderId;

public OrderNotFoundException(long orderId) {


super("Order not found: " + orderId);
[Link] = orderId;
}

Java Exception Handling Interview Prep · Page


public OrderNotFoundException(long orderId, Throwable cause) {
super("Order not found: " + orderId, cause);
[Link] = orderId;
}
public long getOrderId() { return orderId; }
}

💡 Interviewer Tip:
Interviewers at 3-year level expect the four-constructor pattern. Extra credit: mention that domain-specific
fields (orderId) let global exception handlers return structured JSON error responses in Spring.

Q15 What is the 'return value inside finally' trap? [Intermediate]

Answer:
If a finally block contains a return statement, it overrides any return value in the try block — including any exception
that was being thrown. The exception is silently swallowed.
This is one of the nastiest bugs in Java because no stack trace, no warning — the exception just disappears.
Modern linters (Sonar, IntelliJ) flag this as a critical warning. Never return from finally.

public int dangerous() {


try {
throw new RuntimeException("oops");
} finally {
return 42; // Exception is SILENTLY SWALLOWED
}
}
// Caller gets 42 with no indication anything went wrong

// Also applies to return values:


public int test() {
try { return 1; }
finally { return 2; } // Always returns 2, try's 1 is gone
}

💡 Interviewer Tip:
Interviewers LOVE this question. The correct answer is: 'return in finally silently swallows exceptions — this is
always a bug. SonarQube treats it as a blocker.' It shows you've dealt with real production code issues.

Can you rethrow an exception? How does rethrowing work with type inference in Java
Q16 7+? [Intermediate]

Answer:
You can rethrow a caught exception with 'throw e'. Basic rethrowing is straightforward.
Java 7 introduced precise rethrow: if you catch Exception but only throw a narrower type (and don't reassign the
variable), the compiler is smart enough to know only specific types can escape. You can then declare only those specific
types in the throws clause.

Java Exception Handling Interview Prep · Page


// Precise rethrow — Java 7+
void process() throws IOException, SQLException {
try {
riskyOp(); // declares throws IOException, SQLException
} catch (Exception e) {
log(e);
throw e; // compiler knows only IOException|SQLException can escape
}
}
// Without Java 7 precise rethrow, you'd need: throws Exception

💡 Interviewer Tip:
Most candidates don't know about precise rethrow type inference. Mentioning it signals that you read the Java
7 release notes, not just tutorial sites.

Q17 What is exception propagation? How does it flow through the call stack? [Intermediate]

Answer:
When an exception is thrown and not caught in the current method, it propagates up the call stack to the caller. Each
frame is unwound (finally blocks run) until a matching catch is found or the thread terminates.
For checked exceptions, each intermediate method must either catch or declare (throws) the exception — the compiler
enforces this chain.
For unchecked exceptions, the propagation is silent — no declarations required at each level.

// Stack: main() → serviceA() → serviceB() → dao()


// Exception thrown in dao(), not caught there
// → propagates to serviceB() — no catch → finally runs
// → propagates to serviceA() — catch found → handled

void dao() throws SQLException { throw new SQLException(); }


void serviceB() throws SQLException { dao(); } // declares, doesn't handle
void serviceA() {
try { serviceB(); }
catch (SQLException e) { /* handled here */ }
}

💡 Interviewer Tip:
Interviewers sometimes ask: 'What if there are multiple matching catch blocks?' The first matching catch in
order wins. Always order from most specific to most general.

Q18 What is the 'exception swallowing' anti-pattern? [Intermediate]

Answer:
Exception swallowing means catching an exception and doing nothing (or just printing it), allowing the program to
continue as if nothing happened. This is one of the most dangerous Java anti-patterns.
Real consequences: silent data corruption, partially committed transactions, misleading application state.
Java Exception Handling Interview Prep · Page
Acceptable alternatives: log and rethrow, wrap and rethrow, or if you genuinely must ignore (e.g., cleanup), add a
comment explaining why.

// ANTI-PATTERN: Swallowing
try {
[Link]();
} catch (Exception e) {
// TODO fix later ← NEVER do this in production
}

// CORRECT: Log and rethrow


try {
[Link]();
} catch (Exception e) {
[Link]("Commit failed", e);
throw new DataAccessException("Commit failed", e);
}

💡 Interviewer Tip:
At a 3-year experience level, interviewers expect you to proactively mention this as something you watch for in
code reviews. It signals maturity.

Q19 What is StackOverflowError and when does it occur? [Intermediate]

Answer:
StackOverflowError is thrown when the JVM's call stack runs out of space — almost always due to infinite or deeply
recursive method calls.
Each method call frame consumes stack space. The JVM stack has a fixed size (configurable via -Xss). When exceeded,
SOE is thrown.
Can be caught (it's a Throwable) but you almost never should — there's typically no way to recover meaningfully.

// Classic cause: unguarded recursion


public int factorial(int n) {
return n * factorial(n - 1); // forgot base case → SOE
}

// Also caused by: circular toString(), equals() chains,


// Proxy infinite delegation, Spring circular bean dependencies

💡 Interviewer Tip:
Follow-up: 'How would you diagnose SOE in production?' Answer: look at the stack trace — all frames will be
the same method repeating. Increase -Xss only as a last resort; fix the recursion.

Q20 What is OutOfMemoryError and what are its common causes? [Intermediate]

Answer:
OutOfMemoryError is thrown when the JVM cannot allocate an object because the heap is exhausted.
Java Exception Handling Interview Prep · Page
Common causes:
→ Memory leaks (objects referenced longer than needed — e.g., static collections growing unboundedly).
→ Heap too small for the workload (-Xmx not set appropriately).
→ Metaspace exhaustion (too many class definitions, common in environments with lots of dynamic class generation).
→ Large object allocation (loading a huge file into a byte[] all at once).
Diagnosed with heap dumps (-XX:+HeapDumpOnOutOfMemoryError) and tools like Eclipse MAT or JVisualVM.

💡 Interviewer Tip:
Interviewers want to hear 'heap dump' and at least one profiling tool. Mentioning -XX:
+HeapDumpOnOutOfMemoryError and that you've actually analyzed one (even if not) shows operational
maturity.

Q21 How does Java handle exceptions in static initializers? [Intermediate]

Answer:
If a checked exception is thrown inside a static initializer block, it must be caught within the block — you cannot declare
throws on a static initializer.
If an unchecked exception or error escapes a static initializer, the class fails to load. Any subsequent attempt to use that
class throws ExceptionInInitializerError, wrapping the original exception.
After the first failure, subsequent attempts throw NoClassDefFoundError (because the JVM marks the class as failed).

class Config {
static final Properties props;
static {
try {
props = loadConfig(); // might throw IOException
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
}
// First use: ExceptionInInitializerError
// Later uses: NoClassDefFoundError

💡 Interviewer Tip:
ExceptionInInitializerError → NoClassDefFoundError progression is a subtle but real production issue.
Interviewers at senior level often ask about this to check JVM class-loading knowledge.

Q22 What is the difference between printStackTrace() and using a logger? [Intermediate]

Answer:
printStackTrace() writes to [Link] — synchronously, without any timestamp, log level, or correlation ID. In a multi-
threaded application, output from multiple threads interleaves and becomes unreadable.

Java Exception Handling Interview Prep · Page


A proper logger (SLF4J + Logback/Log4j2) provides: log levels (ERROR/WARN), timestamps, thread names, MDC context
(correlation/trace IDs), configurable outputs (file, Splunk, ELK), and async appenders.
In production code, printStackTrace() is always a code smell. Use [Link]('message', e) — this also captures the full
stack trace.

// Wrong
} catch (Exception e) {
[Link](); // no level, no context, no correlation
}

// Correct
} catch (Exception e) {
[Link]("Order processing failed for orderId={}", orderId, e);
}
// Output includes: timestamp, level, thread, correlation ID, stack

💡 Interviewer Tip:
This question tests real production experience. Mentioning MDC (Mapped Diagnostic Context) for correlation
IDs, and structured logging (JSON logs for ELK/Splunk), makes you stand out significantly.

Q23 Can a constructor throw an exception? What happens to the object? [Intermediate]

Answer:
Yes, a constructor can throw any exception (checked or unchecked).
If a constructor throws, the object is never fully constructed. The reference is null (or never assigned). The JVM's
garbage collector will clean up any partially allocated object.
Finalizers (deprecated) on a partially constructed object will NOT be called. This was a historical security concern with
finalizer attacks — addressed by sealing constructors.
Best practice: validate arguments early in the constructor and throw IllegalArgumentException fast.

public class DatabaseConnection {


private final Connection conn;

public DatabaseConnection(String url) throws SQLException {


if (url == null) throw new IllegalArgumentException("url is null");
[Link] = [Link](url);
// If this throws, no object is created
}
}

💡 Interviewer Tip:
Follow-up: 'What if a superclass constructor throws — does the subclass constructor run?' No — the exception
propagates immediately, the subclass constructor body never executes.

Q24 What is NullPointerException? How has Java 14+ improved it? [Intermediate]

Java Exception Handling Interview Prep · Page


Answer:
NullPointerException is thrown when you try to use a null reference: invoking a method on it, accessing a field, or using
it as an array.
Java 14 introduced Helpful NPE messages (JEP 358) — the JVM now tells you exactly which variable was null in the
expression, rather than just the line number.
Java 16+ made this the default behavior (no flag needed). The message reads like: 'Cannot invoke "[Link]()"
because "[Link]" is null'.

// Before Java 14:


// NullPointerException at line 42 (useless!)

// Java 14+ (JEP 358):


String city = [Link]().getCity().toUpperCase();
// NullPointerException: Cannot invoke "[Link]()"
// because the return value of "[Link]()" is null

// Best practice: use Optional<> or null-safe APIs


String city = [Link](user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("Unknown");

💡 Interviewer Tip:
Mentioning JEP 358 and Optional demonstrates you stay current with Java evolution. Interviewers at
companies using Java 17+ LTS will appreciate this.

Q25 What are best practices for exception handling? [Intermediate]

Answer:
1. Be specific — catch the most specific exception type, not Exception or Throwable.
2. Never swallow — always log or rethrow.
3. Preserve the cause — always pass the original exception as the cause when wrapping.
4. Don't use exceptions for flow control — they're expensive and semantically wrong.
5. Prefer unchecked exceptions in modern APIs — reduces boilerplate, aligns with Spring/modern frameworks.
6. Fail fast — validate preconditions early, throw IllegalArgumentException immediately.
7. Use try-with-resources — always, for any AutoCloseable.
8. Document with @throws Javadoc — especially for unchecked exceptions on public APIs.

💡 Interviewer Tip:
At a 3-year level, interviewers expect you to rattle off 5-6 best practices without prompting. 'Exceptions for flow
control is slow' (because stack trace construction is expensive) is a sophisticated point that resonates with
senior engineers.

Java Exception Handling Interview Prep · Page


Quick Reference: Checked vs Unchecked
Aspect Checked vs Unchecked
Compile-time enforcement Checked: enforced by compiler. Unchecked: not.

Extends Checked: Exception (not RuntimeException). Unchecked:


RuntimeException.

Must declare with throws? Checked: YES. Unchecked: NO (optional but good practice).

Typical use case Checked: recoverable (IO, network). Unchecked:


programming bugs.

Spring Framework preference Spring uses exclusively unchecked (DataAccessException


hierarchy).

Modern API design trend Prefer unchecked — reduces boilerplate, cleaner APIs.

Section 3 — Advanced: Architecture, Spring & Tricky Scenarios


Questions 31–50 separate senior candidates. These cover Spring exception handling philosophy, transaction rollback rules,
global exception handlers, and JVM internals.

Q31 Why does Spring use unchecked exceptions? What is DataAccessException? [Advanced]

Answer:
Spring made a deliberate architectural decision to translate all data access exceptions (from JDBC, JPA, Hibernate) into
a hierarchy of unchecked exceptions under DataAccessException.
Reasons:
1. Vendor neutrality — SQLException is database-specific; DataAccessException subtypes are portable.
2. Cleaner code — callers choose whether to handle, without forced try-catch boilerplate.
3. Checked exceptions in large codebases cause 'exception pollution' — every method in the call chain must declare
them.
Rod Johnson (Spring founder) explicitly argued in 'Expert One-on-One J2EE Design and Development' that checked
exceptions are overused and lead to swallowing.

// Old JDBC — checked exception hell


try {
[Link]();
} catch (SQLException e) { ... }

// Spring JdbcTemplate — clean, unchecked


List<User> users = [Link](sql, userRowMapper);
// DataAccessException is thrown if something goes wrong
// You catch it only if you can meaningfully handle it

💡 Interviewer Tip:
This is a litmus test question for 3-year candidates. Being able to explain the philosophy (not just 'Spring uses
unchecked') — and mentioning checked exception pollution — is what gets you to the next round.

Java Exception Handling Interview Prep · Page


How does Spring's @Transactional interact with exception handling? What triggers
Q32 rollback? [Advanced]

Answer:
By default, @Transactional rolls back ONLY on unchecked exceptions (RuntimeException and Error). Checked
exceptions do NOT trigger rollback by default.
You can customize with rollbackFor and noRollbackFor attributes.
Critical: If you catch an exception inside a @Transactional method and don't rethrow it, Spring never sees the exception
and will COMMIT the transaction — potentially corrupting data.

@Transactional
public void placeOrder(Order order) {
[Link](order);
try {
[Link](order);
} catch (PaymentException e) {
[Link]("Payment failed", e);
// DANGER: transaction will COMMIT! order saved, no payment
// FIX: rethrow or call
[Link]().setRollbackOnly()
}
}

@Transactional(rollbackFor = [Link])
public void safePlace(Order order) throws CheckedPaymentException { }

💡 Interviewer Tip:
This is the most common @Transactional bug in production Spring apps. Interviewers at companies using
Spring Boot expect you to know this cold. Mention
[Link]().setRollbackOnly() as a last resort.

Q33 How do you implement global exception handling in Spring Boot? [Advanced]

Answer:
@ControllerAdvice / @RestControllerAdvice: A class annotated with this acts as a global exception handler for all
controllers. Methods annotated with @ExceptionHandler catch specific exception types.
This lets you centralize error response formatting — returning structured JSON (error code, message, timestamp)
instead of Spring's default whitepage error.
You can also implement ResponseEntityExceptionHandler to override Spring MVC's built-in exception handling (e.g.,
MethodArgumentNotValidException for validation).

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse> handleOrderNotFound(
OrderNotFoundException ex, WebRequest request) {
ErrorResponse body = new ErrorResponse(

Java Exception Handling Interview Prep · Page


HttpStatus.NOT_FOUND.value(), [Link](),
[Link]().toString());
return [Link](HttpStatus.NOT_FOUND).body(body);
}

@ExceptionHandler([Link]) // fallback handler


public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
return [Link]()
.body(new ErrorResponse(500, "Unexpected error", ...));
}
}

💡 Interviewer Tip:
Full marks answer: mention ProblemDetail (RFC 9457) introduced in Spring 6 / Spring Boot 3 as the
standardized error response format. Shows you're tracking modern Spring.

What is the difference between @ExceptionHandler in a controller vs


Q34 @ControllerAdvice? [Advanced]

Answer:
@ExceptionHandler inside a @Controller class: applies only to that specific controller. Useful for controller-specific
errors.
@ControllerAdvice: applies globally across all controllers. You can scope it by package, annotation, or class using
basePackages / annotations / assignableTypes.
Resolution order: local @ExceptionHandler in the controller takes priority over global @ControllerAdvice.

@RestController
public class OrderController {
// Only handles exceptions from THIS controller
@ExceptionHandler([Link])
public ResponseEntity<?> handleLocal(OrderNotFoundException e) { ... }
}

// Scoped to a specific package


@ControllerAdvice(basePackages = "[Link]")
public class OrderExceptionHandler { ... }

💡 Interviewer Tip:
Interviewers ask: 'What if both a local handler and a global handler can handle the same exception?' Local
handler wins — it's more specific.

Q35 How do exceptions interact with Java streams and lambdas? [Advanced]

Answer:
Lambdas used in streams (Predicate, Function, Consumer) cannot throw checked exceptions — the functional interface
signature doesn't declare them.
Workarounds:

Java Exception Handling Interview Prep · Page


1. Wrap checked exceptions in RuntimeException inside the lambda.
2. Create a utility method that converts a checked-throwing function to an unchecked one.
3. Use libraries like Vavr's Try or Lombok's @SneakyThrows (which bytecode-hacks checked exception erasure).
Unchecked exceptions in streams terminate the stream and propagate normally.

// Problem: [Link] throws IOException (checked)


List<String> contents = [Link]()
.map(p -> {
try { return [Link](p); }
catch (IOException e) { throw new UncheckedIOException(e); }
})
.collect([Link]());

// Utility wrapper pattern


@FunctionalInterface
interface ThrowingFunction<T,R> {
R apply(T t) throws Exception;
static <T,R> Function<T,R> wrap(ThrowingFunction<T,R> f) {
return t -> { try { return [Link](t); }
catch (Exception e) { throw new RuntimeException(e); } };
}
}

💡 Interviewer Tip:
This reveals real-world Lambda experience. UncheckedIOException (built into JDK) is the 'correct' wrapper for
IOException in streams. Mentioning @SneakyThrows (and its controversy) is a great bonus.

Q36 What is ExceptionInInitializerError? [Advanced]

Answer:
Thrown when an unchecked exception escapes a static initializer block. It wraps the original exception.
After this, every subsequent attempt to reference the class throws NoClassDefFoundError (not EIIE again).
Diagnosed by calling getCause() on the ExceptionInInitializerError to find the root problem.

class AppConfig {
static final String DB_URL = loadFromVault(); // throws RuntimeException
static String loadFromVault() { throw new RuntimeException("vault down"); }
}

// First access:
// [Link]: vault down

// Every subsequent access:


// [Link]: Could not initialize class AppConfig

💡 Interviewer Tip:
The key thing to mention: getCause() reveals the actual problem. NCDFE on subsequent accesses is a common
source of confusion in production diagnostics.

Java Exception Handling Interview Prep · Page


Q37 What is the UncheckedIOException and when should you use it? [Advanced]

Answer:
UncheckedIOException (Java 8+) is an unchecked wrapper for IOException. It's provided by the JDK specifically for use
in contexts that cannot throw checked exceptions — streams, lambdas, method references.
Use it instead of a raw RuntimeException wrapper because: it preserves semantic meaning (this was an IO problem),
getCause() returns IOException directly, and catch (UncheckedIOException) lets callers selectively handle IO failures
without catching all RuntimeExceptions.

// Use UncheckedIOException, not raw RuntimeException


[Link]().map(path -> {
try { return [Link](path); }
catch (IOException e) {
throw new UncheckedIOException(e); // JDK-provided wrapper
}
})

// Caller can selectively catch:


.forEach(content -> {
try { process(content); }
catch (UncheckedIOException e) {
[Link]("Skipping unreadable file", [Link]());
}
});

💡 Interviewer Tip:
Most candidates just say 'wrap in RuntimeException'. Knowing UncheckedIOException exists (and why it's
better) is a distinguishing answer.

How do you handle exceptions in asynchronous code (@Async, CompletableFuture)?


Q38 [Advanced]

Answer:
@Async methods return CompletableFuture. Exceptions thrown inside are not propagated to the caller's thread —
they're stored in the future and only surface when you call .get().
CompletableFuture wraps exceptions in CompletionException (for thenApply etc.) or ExecutionException (for .get()).
For @Async, implement AsyncUncaughtExceptionHandler to globally handle exceptions from void @Async methods.
For CompletableFuture, use .exceptionally() or .handle() to react to failures without blocking.

// CompletableFuture exception handling


CompletableFuture<Order> future = CompletableFuture
.supplyAsync(() -> fetchOrder(id)) // exception stored here
.exceptionally(ex -> {
[Link]("Order fetch failed", ex);
return [Link]();
})
.thenApply(order -> enrich(order));

// @Async void method handler

Java Exception Handling Interview Prep · Page


@Configuration
class AsyncConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) ->
[Link]("Async error in {}", [Link](), ex);
}
}

💡 Interviewer Tip:
This is a strong differentiator question. CompletionException vs ExecutionException distinction (thenApply
wraps in CompletionException; .get() wraps in ExecutionException) is the kind of detail that shows real async
experience.

What is the difference between fail-fast and fail-safe iterators in terms of exceptions?
Q39 [Advanced]

Answer:
Fail-fast iterators (ArrayList, HashMap): throw ConcurrentModificationException immediately if the collection is
structurally modified during iteration (outside the iterator itself). They check an internal modCount.
Fail-safe iterators (CopyOnWriteArrayList, ConcurrentHashMap): iterate over a snapshot/clone and never throw
ConcurrentModificationException — but they may not reflect recent modifications.
Neither guarantees thread safety in the general sense; fail-safe just avoids the exception by trading memory (copy) for
consistency.

List<String> list = new ArrayList<>([Link]("a", "b", "c"));


for (String s : list) {
if ([Link]("b")) [Link](s); // throws ConcurrentModificationException
}

// Fix 1: [Link]()
Iterator<String> it = [Link]();
while ([Link]()) {
if ([Link]().equals("b")) [Link](); // safe
}

// Fix 2: removeIf (Java 8)


[Link](s -> [Link]("b"));

💡 Interviewer Tip:
ConcurrentModificationException is not just a threading issue — it happens on a single thread if you modify
during enhanced-for iteration. This distinction is commonly missed.

Q40 What is the cost of exceptions in Java? Should you use them for control flow? [Advanced]

Answer:

Java Exception Handling Interview Prep · Page


Creating an exception object involves walking the call stack to capture the stack trace — this is the expensive part
(fillInStackTrace()). On a modern JVM, this can take microseconds to milliseconds depending on stack depth.
Using exceptions for flow control (e.g., catching NumberFormatException to detect non-numeric input) is a well-known
anti-pattern because:
1. Performance: stack trace creation on every non-numeric input.
2. Semantics: exceptions should represent exceptional conditions, not expected logic branches.
Optimization: you can subclass RuntimeException and override fillInStackTrace() to return 'this' (no-op), creating a
lightweight exception for flow control in performance-critical code.

// Anti-pattern: exception as control flow


try {
int val = [Link](input);
} catch (NumberFormatException e) {
// Using NFE to detect non-numeric — wasteful
}

// Correct: validate first


if ([Link]("\\d+")) {
int val = [Link](input);
}

// Lightweight exception (override fillInStackTrace)


class FlowException extends RuntimeException {
@Override public Throwable fillInStackTrace() { return this; }
}

💡 Interviewer Tip:
Mentioning fillInStackTrace() override is an advanced technique that very few candidates know. It's used in
frameworks like Netty for internal flow control. It signals you understand JVM performance.

What exception is thrown when you access an invalid array index, null, or divide by
Q41 zero? [Basic]

Answer:
ArrayIndexOutOfBoundsException: accessing arr[-1] or arr[[Link]].
NegativeArraySizeException: creating an array with negative size: new int[-1].
NullPointerException: dereferencing a null reference.
ArithmeticException: integer division by zero (int a = 5/0). Note: floating point division by zero returns Infinity, not an
exception.
ClassCastException: invalid cast: (String) new Object().
These are all unchecked (RuntimeException subclasses).

int[] arr = new int[3];


arr[5] = 1; // ArrayIndexOutOfBoundsException

String s = null;
[Link](); // NullPointerException

int x = 5 / 0; // ArithmeticException: / by zero


double d = 5.0 / 0; // NOT an exception — returns Infinity

Java Exception Handling Interview Prep · Page


Object obj = "hello";
Integer i = (Integer) obj; // ClassCastException

💡 Interviewer Tip:
Floating-point division by zero returning Infinity (not an exception) trips up many candidates. Always worth
mentioning.

Q42 How does exception handling work with Java generics (type erasure)? [Advanced]

Answer:
You CANNOT create a generic exception class: 'class MyException<T> extends Exception' will not compile because you
cannot catch a generic type (type erasure means the JVM can't distinguish MyException<String> from
MyException<Integer> at catch time).
You CAN use generics in methods that throw exceptions — the @SuppressWarnings("unchecked") trick or bounded
wildcards can help.
You CANNOT use a type parameter in a catch clause: catch (T e) is illegal.

// Illegal — generic exception class


class MyException<T> extends Exception { } // COMPILE ERROR

// Legal — generic method that propagates typed exceptions


public <T, E extends Exception> T execute(
ThrowingSupplier<T, E> action) throws E {
return [Link]();
}

// Illegal — type parameter in catch


public <E extends Exception> void bad() {
try { ... }
catch (E e) { } // COMPILE ERROR
}

💡 Interviewer Tip:
This is a niche but high-signal question that tests both generics and exception knowledge simultaneously. The
reason generic exceptions are disallowed is purely due to type erasure — the bytecode catch table uses raw
types.

What is try-with-resources with multiple resources and what order do they close?
Q43 [Advanced]

Answer:
When multiple resources are declared in try-with-resources, they close in REVERSE order of declaration.
This mirrors the natural stack-based cleanup order — the last resource opened is the first to close, since later resources
may depend on earlier ones.

Java Exception Handling Interview Prep · Page


Each close() is called independently. If one throws, others still close, and subsequent close() exceptions are added as
suppressed exceptions on the first.

try (Connection conn = [Link](); // opened 1st


PreparedStatement ps = [Link](sql); // opened 2nd
ResultSet rs = [Link]()) { // opened 3rd
while ([Link]()) { process(rs); }
}
// Close order: rs → ps → conn (reverse of declaration)
// If [Link]() throws AND [Link]() throws:
// → rs exception propagates
// → ps exception added as suppressed to rs exception

💡 Interviewer Tip:
Reverse close order is a frequently tested detail. The suppression behavior for multiple close failures is a rarer
but impressive addition to the answer.

How does exception handling differ between Thread and Executor/thread pool?
Q44 [Advanced]

Answer:
In a plain Thread, you can set an UncaughtExceptionHandler to capture unchecked exceptions that escape the run()
method.
In ExecutorService (thread pool), exceptions from submitted Runnables are silently swallowed unless you call
[Link](). Exceptions from Callables are wrapped in ExecutionException and surface on .get().
This silent swallowing in ExecutorService is a notorious source of bugs — tasks fail with no visible error.

// Plain Thread
Thread t = new Thread(riskyTask);
[Link]((thread, ex) ->
[Link]("Thread {} failed", [Link](), ex));
[Link]();

// ExecutorService — exception silently lost for Runnable


ExecutorService pool = [Link](4);
[Link](() -> { throw new RuntimeException("lost!"); });
// ^^^^ Exception is GONE unless you call [Link]()

// Solution: always use Callable and .get(), or wrap Runnable


Future<?> f = [Link](riskyRunnable);
try { [Link](); }
catch (ExecutionException e) { log([Link]()); }

💡 Interviewer Tip:
Silent exception swallowing in thread pools is a real production bug pattern. Interviewers from companies with
high concurrency requirements (fintech, e-commerce) often ask this specifically.

Q45 What is the difference between initCause() and the constructor cause parameter?

Java Exception Handling Interview Prep · Page


[Advanced]

Answer:
Both set the cause of an exception, but they differ in usability and constraints:
Constructor: new RuntimeException(message, cause) — preferred, sets cause at creation time, immutable after.
initCause(): can only be called ONCE, and only if the cause was not already set in the constructor. Throws
IllegalStateException on second call.
initCause() exists for pre-Java-1.4 exceptions that didn't have cause-aware constructors (e.g., some legacy APIs).

// Preferred: constructor with cause


throw new ServiceException("Failed", originalException);

// Legacy pattern: initCause()


LegacyException ex = new LegacyException("msg");
[Link](originalException); // OK — first call
[Link](anotherException); // throws IllegalStateException!

// Dangerous double-init
RuntimeException e = new RuntimeException("msg", cause1);
[Link](cause2); // IllegalStateException — cause already set

💡 Interviewer Tip:
The one-time-only constraint on initCause() is a classic trick question. The safe answer: always prefer the
constructor form.

Q46 How do you handle exceptions in Spring Batch or scheduled jobs? [Advanced]

Answer:
In Spring Batch, exceptions can be configured to trigger retry, skip, or step failure at the StepBuilder level.
For @Scheduled methods, exceptions are caught by the task scheduler. By default they're logged and the next
execution proceeds. You should implement ErrorHandler or AsyncUncaughtExceptionHandler.
Best pattern: wrap the scheduled job body in try-catch, emit metrics (Micrometer), and alert on repeated failures.

@Scheduled(fixedDelay = 60_000)
public void runJob() {
try {
[Link](importJob, new JobParameters());
} catch (JobExecutionException e) {
[Link]("Scheduled job failed", e);
[Link]("[Link]").increment();
[Link]("Job failed: " + [Link]());
}
}

// Spring Batch: skip specific exceptions


[Link]("step")
.<Input,Output>chunk(100)
.faultTolerant()
.skip([Link]).skipLimit(10)
.retry([Link]).retryLimit(3)
.build();

Java Exception Handling Interview Prep · Page


💡 Interviewer Tip:
Mentioning Micrometer for metrics on exception rates shows operational maturity. In SRE-conscious
companies this is exactly what separates 3-year candidates from junior ones.

What happens when you call getMessage(), getCause(), and toString() on an exception?
Q47 [Advanced]

Answer:
getMessage(): returns the detail message string passed to the constructor. May be null.
getLocalizedMessage(): by default same as getMessage(), but subclasses can override for locale-specific messages.
getCause(): returns the Throwable that caused this exception, or null if none.
toString(): returns className + ': ' + message (e.g., [Link]: oops).
printStackTrace(): prints toString() then the stack trace to [Link], including any chained causes.

RuntimeException e = new RuntimeException(


"connection failed",
new IOException("timeout"));

[Link](); // "connection failed"


[Link](); // [Link]: timeout
[Link](); // [Link]: connection failed
// printStackTrace() output:
// [Link]: connection failed
// at ...
// Caused by: [Link]: timeout
// at ...

💡 Interviewer Tip:
A quick-fire question to test basic Throwable API knowledge. Knowing getLocalizedMessage() and that
toString() is what [Link](exception) calls will show depth.

Q48 How do you write unit tests for exception handling? [Advanced]

Answer:
JUnit 5: use assertThrows() to verify that specific code throws a specific exception type. You can then assert on the
exception message, cause, or custom fields.
assertDoesNotThrow() verifies no exception is thrown.
Mockito: use thenThrow() to simulate exception scenarios from dependencies.
Best practice: test both the exception type AND the message/cause to ensure useful error messages reach callers.

// JUnit 5
@Test
void shouldThrowWhenOrderNotFound() {

Java Exception Handling Interview Prep · Page


OrderNotFoundException ex = assertThrows(
[Link],
() -> [Link](999L)
);
assertEquals(999L, [Link]());
assertEquals("Order not found: 999", [Link]());
}

// Mockito: simulate dependency failure


@Test
void shouldWrapDataAccessException() {
when([Link](1L)).thenThrow(new DataAccessException("DB down"){});
ServiceException ex = assertThrows([Link],
() -> [Link](1L));
assertInstanceOf([Link], [Link]());
}

💡 Interviewer Tip:
The assertThrows + field assertion pattern is expected at a 3-year level. Testing that the cause is correctly
chained ([Link]() instanceof ...) shows you care about debuggability.

Q49 What is the role of exception handling in microservices (REST APIs)? [Advanced]

Answer:
In microservices, exceptions must be translated into meaningful HTTP responses with standard error formats. Key
concerns:
1. Error response structure: use ProblemDetail (RFC 9457 / Spring 6) or a custom ErrorResponse DTO.
2. HTTP status mapping: 404 for not found, 400 for validation errors, 409 for conflicts, 500 for unexpected.
3. Don't expose internals: never return stack traces, SQL errors, or internal class names to API consumers.
4. Correlation IDs: include a trace/correlation ID in error responses so clients can report issues.
5. Circuit breaker exceptions: handle Resilience4j's CallNotPermittedException for degraded-mode responses.

// ProblemDetail (Spring 6 / RFC 9457)


@ExceptionHandler([Link])
public ProblemDetail handleNotFound(OrderNotFoundException ex,
HttpServletRequest req) {
ProblemDetail pd = [Link](
HttpStatus.NOT_FOUND, [Link]());
[Link]("Order Not Found");
[Link]("orderId", [Link]());
[Link]("traceId", [Link]("traceId"));
return pd;
}

💡 Interviewer Tip:
ProblemDetail RFC 9457 support in Spring Boot 3 is the current industry standard. Mentioning never exposing
stack traces to external clients (security concern, information leakage) is essential.

Java Exception Handling Interview Prep · Page


Q50 Describe a real-world exception handling bug you've seen or fixed. [Advanced]

Answer:
This open-ended question tests practical experience. Strong answers follow the STAR pattern (Situation, Task, Action,
Result) and demonstrate real debugging skills.
Example scenario: A @Transactional service method caught an exception internally to log it, without rethrowing. The
transaction committed despite a failed downstream call, leaving the database in an inconsistent state.
Investigation: Spring's transaction interceptor never saw the exception, so rollback was never triggered.
Fix: Rethrow a RuntimeException (or call setRollbackOnly()), or restructure to not catch inside the transactional
boundary.
Lesson: Always be aware of where your @Transactional boundary is relative to your try-catch blocks.

// The bug
@Transactional
public void processOrder(Order order) {
[Link](order);
try {
[Link](order); // throws!
} catch (Exception e) {
[Link]("inventory failed", e); // swallowed → commit!
}
}

// The fix
@Transactional
public void processOrder(Order order) {
[Link](order);
try {
[Link](order);
} catch (Exception e) {
[Link]("inventory failed", e);
throw new OrderProcessingException("Inventory reservation failed", e);
}
}

💡 Interviewer Tip:
Interviewers use this question to gauge real experience vs theoretical knowledge. A crisp STAR answer about
@Transactional + exception swallowing, or a CompletableFuture silent failure, immediately signals production-
level thinking.

Quick-Revision Cheat Sheet


Exception / Concept Key Fact to Remember
Throwable Root of all exceptions and errors

Error JVM-level, almost never catch

RuntimeException Unchecked — no compile enforcement

Java Exception Handling Interview Prep · Page


Checked Exception Must catch or declare; compiler-enforced

finally Always runs except [Link]() or JVM crash

return in finally Overrides try return AND swallows exceptions — never do


this

try-with-resources Closes AutoCloseable in reverse order

Suppressed exceptions TWR: close() exception stored via addSuppressed()

Multi-catch Uses |, parameter is effectively final

initCause() One-time-only; prefer constructor with cause

ClassNotFoundException Dynamic load ([Link]) failed

NoClassDefFoundError Class was present at compile, missing at runtime

ExceptionInInitializerError Unchecked escaping static {}; subsequent = NCDFE

@Transactional rollback Default: unchecked only. Customize with rollbackFor

@ControllerAdvice Global exception handler across all controllers

DataAccessException Spring's unchecked hierarchy over vendor SQLExceptions

fillInStackTrace() Override to no-op for lightweight flow-control exceptions

UncheckedIOException JDK 8+ wrapper for IOException in streams/lambdas

ExecutorService Runnable exceptions silently lost unless [Link]() called

ProblemDetail (RFC 9457) Standard error response format in Spring 6 / Boot 3

Good luck with your interviews! ☕

Java Exception Handling Interview Prep · Page

You might also like