Exception Interview Preparation
Top 15 Exception Interview Questions (Highest Priority) If you have limited preparation time, master these first: What is an Exception? Checked vs Unchecked Exception. Throwable vs Exception vs…
Top 15 Exception Interview Questions (Highest Priority)
If you have limited preparation time, master these first:
- What is an Exception? Checked vs Unchecked Exception.
- Throwable vs Exception vs Error.
throwvsthrows.try-catch-finallyexecution flow.- Does
finallyexecute afterreturn? - Can
finallybe skipped? - Exception propagation and stack unwinding.
- Rules for exceptions in method overriding.
- Try-with-Resources and
AutoCloseable. @ExceptionHandlervs@RestControllerAdvice.- Handling
MethodArgumentNotValidException. @Transactionalrollback rules (rollbackFor,noRollbackFor).- Designing a production-ready REST API exception strategy.
- Exception translation and exception chaining.
- How to create and use custom business exceptions in Spring Boot.
A. Exception Basics
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
An Exception is an event that occurs during program execution which disrupts the normal flow of the program.
It represents an unexpected situation, such as invalid input, dividing by zero, accessing a null object, or reading a missing file.
In Java, every exception is an object that extends the Throwable class.
Examples
- ArithmeticException
- NullPointerException
- IOException
- SQLException
Interview One-liner: An exception is an abnormal event that interrupts the normal execution of a program. Java represents exceptions as objects derived from the Throwable class.
Without exception handling, whenever an exception occurs, the program terminates immediately.
Exception handling helps us:
- Prevent application crashes
- Separate normal logic from error handling
- Maintain application flow
- Provide meaningful error messages
- Clean up resources properly
- Build reliable enterprise applications
Example
Without exception handling
int result = 10 / 0;
System.out.println("Completed");
Program terminates.
With handling
try {
int result = 10 / 0;
} catch(Exception e) {
System.out.println(e.getMessage());
}
System.out.println("Completed");
Output
/ by zero
Completed
Interview Tip: Exception handling improves robustness, maintainability, and user experience.
Java follows a hierarchy starting from Throwable.
Object
│ Throwable /
Exception Error
/
Checked RuntimeException
| Unchecked Exceptions Checked Exceptions
Examples
- IOException
- SQLException
- FileNotFoundException
Compiler forces handling.
Runtime Exceptions
Examples
- NullPointerException
- ArithmeticException
- ArrayIndexOutOfBoundsException
Compiler does not force handling.
Errors
Examples
- OutOfMemoryError
- StackOverflowError
Generally not handled.
Interview One-liner: Throwable is the root class. Exception represents recoverable conditions, whereas Error represents serious JVM problems.
These three sit at the top of Java’s exception model and interviewers often ask how they differ.
| Type | Meaning |
|---|---|
| Throwable | Root of the hierarchy. Parent of Exception and Error. |
| Exception | Recoverable conditions your application can catch and handle (checked or unchecked). |
| Error | Serious JVM/system problems (e.g. OutOfMemoryError). Usually not caught. |
Follow-up: Why don’t we catch Error?
Because Errors indicate serious JVM issues from which recovery is usually impossible.
Interview One-liner: Catch Exception for recoverable problems; avoid catching Error unless you have a very specific recovery strategy.
Checked and unchecked exceptions differ in when they are detected and whether the compiler forces handling.
| Checked | Unchecked |
|---|---|
| Detected at compile time | Detected at runtime |
| Must be handled with try-catch or declared with throws | Not required to handle or declare |
| Usually recoverable external conditions (I/O, SQL, files) | Usually programming mistakes (null, bad index, illegal args) |
| Subclass of Exception (excluding RuntimeException) | Subclass of RuntimeException (or Error) |
Checked examples
- IOException
- SQLException
- FileNotFoundException
Unchecked examples
- NullPointerException
- ArithmeticException
- IllegalArgumentException
Interview One-liner: Checked exceptions represent recoverable external conditions, while unchecked exceptions usually indicate programming mistakes.
Compile-time Exception
Detected during compilation.
Example
FileReader reader = new FileReader("abc.txt");
Compiler forces handling.
Runtime Exception
Occurs while the program executes.
Example
String s = null;
s.length();
Compiles successfully.
Fails at runtime.
Most frequently asked:
Interview Tip: These are mostly caused by programming mistakes.
Most important ones:
B. try-catch-finally
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Internally, the JVM monitors the try block.
Executes statements inside try.
If no exception occurs, all catch blocks are skipped.
If an exception occurs, JVM creates an exception object.
JVM searches for the first matching catch.
Executes the matching catch.
Executes finally (if present).
If no matching catch is found, the exception propagates to the caller.
Interview One-liner: The JVM throws an exception object, searches for the first compatible catch block, executes it, then runs finally before continuing or propagating the exception.
Yes.
try {
} catch(IOException e) {
} catch(SQLException e) {
} catch(Exception e) {
}
The JVM executes only the first matching catch block.
Catch blocks must be ordered from most specific to most general.
Correct:
catch(FileNotFoundException e)
catch(IOException e)
catch(Exception e)
Wrong:
catch(Exception e)
catch(IOException e)
Compiler Error:
- Unreachable catch block
Interview Tip: Always place child exceptions before parent exceptions.
Yes.
Using finally.
try {
} finally{
}
Yes.
try {
} catch(Exception e) {
}
Yes.
try {
} finally{
}
Normally No.
But it may not execute when:
- JVM crashes
System.exit()
Power failure
OS crash
Infinite loop before reaching finally
Example
System.exit(0);finally won't execute.
Interview Tip: This is a very common interview question.
Yes.
Example
public int test() {
try {
return 10;
} finally{
System.out.println("Finally");
}
}
Output
Finally
Return value:
10
Interview One-liner: The return value is prepared first, then finally executes, and only afterward is the value returned.
The exception from finally overrides any previous normal flow.
Example
try {
return;
} finally{ throw new RuntimeException();}
Return never happens.
The exception is thrown.
The exception from finally takes precedence, and the one thrown in catch is lost (unless explicitly preserved using suppressed exceptions or other mechanisms).
Example
try {
throw new Exception("Try");
} catch (Exception e) {
throw new RuntimeException("Catch");
} finally {
throw new IllegalStateException("Finally");
}
The caller receives:
- IllegalStateException: Finally
Interview Tip: Avoid throwing exceptions from finally because it can hide the original exception, making debugging difficult.
C. throw & throws
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Example
throw new IllegalArgumentException("Invalid age");public void readFile() throws IOException {
// code
}
Interview One-liner: throw actually throws an exception object, whereas throws tells the caller which exceptions the method may propagate.
class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}
Usage:
if(age < 18) {
throw new InvalidAgeException("Age must be 18 or above");
}
throws delegates exception handling to the caller instead of handling it inside the method.
Benefits
- Cleaner code
- Separation of concerns
- Caller decides how to handle the exception
- Common in service and DAO layers
Example
public void loadFile() throws IOException {
// file operation
}
No, unless they are caught within the same method.
Example (Compilation Error):
public void test() { throw new IOException();}
Correct:
public void test() throws IOException { throw new IOException();}
or
public void test() { try { throw new IOException(); } catch (IOException e) {
// handle
}
}
Interview Tip: Checked exceptions must either be caught or declared.
A single throw statement throws only one exception object.
However, a method can declare multiple exception types using throws.
public void process() throws IOException, SQLException {
// code
}
Depending on the execution path, either exception may be thrown.
Yes.
public static void main(String[] args) throws Exception {
throw new Exception("Error");
}
The JVM catches any uncaught exception from main() and prints the stack trace before terminating the program.
Interview Tip: Although allowed, production code should generally handle expected exceptions instead of propagating them from main().
D. Custom Exceptions
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Custom exceptions represent business-specific error scenarios that built-in Java exceptions cannot clearly express.
Benefits
- Improves readability
- Makes error handling meaningful
- Separates business errors from system errors
- Easy integration with Spring Boot global exception handling (@ControllerAdvice)
Examples
- UserAlreadyExistsException
- ResourceNotFoundException
- InvalidOrderStateException
Interview One-liner: Custom exceptions make business rules explicit and produce cleaner, more maintainable error handling.
Checked Custom Exception
class PaymentFailedException extends Exception {
public PaymentFailedException(String msg) {
super(msg);
}
}
Use when the caller is expected to recover or must handle the condition.
Runtime Custom Exception
class InvalidUserException extends RuntimeException {
public InvalidUserException(String msg) {
super(msg);
}
}
Use for validation failures, business rule violations, and invalid API requests. This is the most common approach in Spring Boot applications.
Interview Tip: In modern Spring Boot applications, custom exceptions typically extend RuntimeException and are translated into HTTP responses by a global exception handler.
A good business exception should:
- Represent a single business rule violation.
- Have a meaningful name (for example, InsufficientBalanceException).
- Carry a clear message.
- Extend RuntimeException in most Spring Boot applications.
Be mapped to an appropriate HTTP status using global exception handling.
Example
public class InsufficientBalanceException extends RuntimeException {
public InsufficientBalanceException(String message) {
super(message);
}
}
public class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}
}
Usage:
if (email == null || email.isBlank()) {
throw new ValidationException("Email is required");
}
In Spring Boot, this can be converted into a 400 Bad Request response.
A very common exception in REST APIs when a requested resource does not exist.
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
Usage:
User user = repository.findById(id)
.orElseThrow(() ->
new ResourceNotFoundException("User not found"));
Typically mapped to HTTP 404 Not Found.
Used when attempting to create a resource that already exists.
public class DuplicateResourceException extends RuntimeException {
public DuplicateResourceException(String message) {
super(message);
}
}
Usage:
if (repository.existsByEmail(email)) {
throw new DuplicateResourceException("Email already exists");
}
Typically mapped to HTTP 409 Conflict.
E. Method Overriding & Exceptions
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
When a child class overrides a parent method:
- Rule 1: Checked exceptions
- Child can throw the same checked exception
- Child can throw a subclass (narrower) checked exception
- Child cannot throw a broader/new checked exception
- Rule 2: Runtime exceptions
Child method can throw:
- Same runtime exception
- New runtime exception
- Multiple runtime exceptions
- No restriction.
- Rule 3: Parent throws nothing
- If parent method doesn’t throw checked exception,
- Child also cannot throw checked exception.
- But child can throw runtime exception.
Interview One-liner: Checked exceptions follow strict overriding rules, whereas runtime exceptions have no such restriction.
No.
Example
class Parent { void read() throws IOException {}}
class Child extends Parent {
// Compilation Error
void read() throws Exception {}}
Reason:
- Exception is broader than IOException.
- Compiler error.
Interview Tip: The child method cannot increase the exception responsibility of the caller.
Yes.
Example
class Parent { void read() throws IOException {}}
class Child extends Parent {
@Override
void read() throws FileNotFoundException {}
}
Since
FileNotFoundException
↓
IOException
This is perfectly valid.
Interview One-liner: Child methods can always throw the same or a subclass of the checked exception declared by the parent.
Runtime exceptions are not checked by the compiler.
Hence child class can throw
Any RuntimeException
New RuntimeException
Multiple RuntimeExceptions
Example
class Parent {
void test() {}
}
class Child extends Parent{
@Override
void test() {
throw new NullPointerException();
}
}
Valid.
Interview Tip: Runtime exceptions have no overriding restriction.
Constructors can throw exceptions, including checked exceptions.
Example
class Employee {
Employee() throws IOException{
}
}
Object creation
Employee e = new Employee();
Must either
try { Employee e = new Employee();} catch(IOException e) {
}
or
public static void main(String[] args)throws IOException{
}
Important Interview Points
Constructors
✔ Can throw checked exceptions
✔ Cannot be overridden
✔ Therefore overriding rules do not apply
F. Exception Propagation
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Exception propagation is the process where an exception is passed from the method where it occurs to its caller, continuing up the call stack until it is handled or reaches the JVM.
If no matching handler is found, the JVM terminates the program and prints the stack trace.
Example
void c() {
int x = 10/0;
}
void b() {
c();
}
void a() {
b();
}
Propagation
c()
↓
b()
↓
a()
↓
main()
↓
JVM
Interview One-liner: Exceptions travel up the call stack until a matching catch block handles them.
When an exception occurs,
the JVM
stops normal execution
removes stack frames one by one
searches each caller for a matching catch block
This process is called Stack Unwinding.
Example
main()
↓
login()
↓
authenticate()
↓
database()
← Exception occurs
Stack unwinds
database()
↑
authenticate()
↑
login()
↑
main()
Interview Tip: Stack unwinding is how exception propagation is implemented internally by the JVM.
Checked exceptions also propagate, but they must be caught or declared at every level.
Example
void c() throws IOException {}
void b() throws IOException {
c();
}
void a() throws IOException {
b();
}
Eventually
try {
a();
} catch(IOException e) {
}
Interview One-liner: Checked exceptions propagate through method calls, but every method in the chain must either handle them or declare them.
Runtime exceptions propagate automatically.
No throws declaration is required.
Example
void c() {
String s = null;
s.length();
}
Propagation
c()
↓
b()
↓
a()
↓
main()
↓
JVM
Interview Tip: Runtime exceptions don’t require explicit declaration because they extend RuntimeException.
Example
public class Demo {
static void c() {
int x = 10/0;
}
static void b() {
c();
}
static void a() {
b();
}
public static void main(String[] args) {
try {
a();
} catch(Exception e) {
System.out.println("Handled");
}
}
}
Output
Handled
Interview One-liner: Only one catch block at a higher level can handle an exception propagated through multiple nested method calls.
G. Java 7+ Features
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Introduced in Java 7, try-with-resources automatically closes resources after execution, even if an exception occurs.
It eliminates the need for an explicit finally block for resource cleanup.
Example
try(FileReader reader = new FileReader("abc.txt")) {
// use reader
} catch(IOException e) {
}
Automatically closes
reader.close();
Benefits
- Cleaner code
- No resource leak
- Automatic cleanup
- Less boilerplate
Interview One-liner: Try-with-resources automatically closes resources that implement AutoCloseable.
AutoCloseable is an interface introduced in Java 7.
Any class implementing it can be used in try-with-resources.
Interface
public interface AutoCloseable {
void close() throws Exception;
}
Example
class MyResource implements AutoCloseable{
@Override
public void close() {
System.out.println("Closed");
}
}
Interview Tip: All JDBC resources implement AutoCloseable.
Interview One-liner: “Closeable is a specialized AutoCloseable for I/O resources.”
In try-with-resources, if:
- the try block throws an exception, and
- close() also throws an exception,
the exception from close() is suppressed instead of replacing the original exception.
The primary exception is propagated, and suppressed exceptions can be obtained using getSuppressed().
Interview Tip: Without try-with-resources, an exception in finally could hide the original exception. Try-with-resources avoids this problem.
Introduced in Java 7.
Allows handling multiple exception types using one catch block.
Example
try {
} catch(IOException | SQLException e) {
System.out.println(e.getMessage());
}
Benefits
- Less duplicate code
- Cleaner handling
- Better readability
- Important Rule
- Related exceptions cannot be used together.
- Wrong
catch(IOException | Exception e)
Compiler Error
Because IOException is already covered by Exception.
H. Exception Handling Best Practices
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Catch the most specific exception.
Never swallow exceptions silently.
Don’t use exceptions for normal program flow.
Log exceptions with context.
Use custom exceptions for business rules.
Add meaningful error messages.
Close resources using try-with-resources.
Preserve the original cause when wrapping exceptions.
Translate low-level exceptions into business-level exceptions where appropriate.
Interview One-liner: Handle exceptions where you can recover, propagate them where you can’t.
Exception is too generic.
Problems
Hides the real exception type
Makes debugging difficult
Can accidentally catch exceptions you didn’t intend to handle
Encourages poor error handling
Bad
catch(Exception e) {
}
Better
catch(IOException e) {
}
Interview Tip: Catch the most specific exception possible.
Throwable includes both:
- Exception
- Error
Catching Throwable also catches serious JVM errors like:
- OutOfMemoryError
- StackOverflowError
- These are generally not recoverable.
Interview One-liner: Catching Throwable is discouraged because it also catches JVM Errors that applications usually cannot recover from.
Ignoring exceptions means catching them without taking any action.
Example
try {
// code
} catch(Exception e) {
}
Problems
Bugs remain hidden
Difficult debugging
Silent failures
Data inconsistency
Production issues
Instead
Log it
Handle it
Rethrow it if necessary
Logging
Use when you are handling the exception at the current layer.
catch(IOException e) {
logger.error("File read failed", e);
}
Rethrowing
Use when the current layer cannot recover and a higher layer should decide how to respond.
catch(IOException e) {
throw new RuntimeException("Unable to process file", e);
}
Interview Tip: Avoid logging and rethrowing the same exception at multiple layers, as this often leads to duplicate log entries.
Wrapping means catching a low-level exception and throwing a higher-level exception while preserving the original cause.
Example
try {
repository.save(user);
} catch(SQLException e) {
throw new DataAccessException(
"Unable to save user", e);
}
Benefits
- Cleaner API
- Hides implementation details
- Preserves root cause using the cause (e)
Interview One-liner: Wrap exceptions to expose meaningful business errors while preserving the original cause.
Good exception messages help developers quickly identify the problem.
Bad
Error
Good
User with id 101 not found
or
Order 5001 cannot be cancelled because it is already shipped.
Good messages should include relevant business context without exposing sensitive information like passwords or database details.
Exception translation is the practice of converting low-level technical exceptions into higher-level business or application exceptions that make sense to the caller.
Example
try {
repository.findById(id);
} catch (SQLException e) {
throw new DataAccessException(
"Failed to fetch user from database", e);
}
In Spring, this pattern is used extensively—for example, low-level SQLExceptions are translated into exceptions in the DataAccessException hierarchy.
I. Spring Boot Exception Handling
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
@ExceptionHandler is used to handle specific exceptions thrown by controller methods.
Instead of writing try-catch in every API, Spring automatically invokes the annotated method whenever the specified exception occurs.
Example
@RestController
public class UserController {
@GetMapping("/users/{id}") public User getUser(@PathVariable Long id) {
throw new ResourceNotFoundException("User not found");
}
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleException(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ex.getMessage());
}
}
Interview One-liner: @ExceptionHandler handles specific exceptions within a controller.
@ControllerAdvice provides global exception handling across all controllers.
Instead of defining exception handlers in every controller, we centralize them in one class.
Example
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handle(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ex.getMessage());
}
}
Advantages
- Centralized exception handling
- Cleaner controllers
- Reusable
- Easy maintenance
Interview One-liner: @ControllerAdvice centralizes exception handling across all controllers.
Internally
@RestControllerAdvice
=
@ControllerAdvice
+
@ResponseBody
Interview Tip: For REST APIs, always prefer @RestControllerAdvice.
Global Exception Handling means handling all application exceptions in one central place using @RestControllerAdvice.
Benefits
- Consistent API responses
- No duplicate try-catch blocks
- Easier maintenance
- Centralized logging
Example
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiError> handle(Exception ex) {
ApiError error = new ApiError(
LocalDateTime.now(),
500,
"Internal Server Error",
ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(error);
}
}
ResponseEntityExceptionHandler is a Spring-provided base class that already handles many common Spring MVC exceptions.
We extend it to customize default behavior.
Example
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
}
Common exceptions handled
MethodArgumentNotValidException
HttpMessageNotReadableException
HttpRequestMethodNotSupportedException
MissingServletRequestParameterException
Interview Tip: Use it to avoid writing handlers for common framework exceptions from scratch.
Instead of returning plain strings, return a structured JSON response.
Example
public class ApiError {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}
Example Response
{
"timestamp": "2026-07-26T10:30:00",
"status": 404,
"error": "Not Found",
"message": "User not found",
"path": "/users/10"
}
Benefits
- Consistent API format
- Easy frontend integration
- Better debugging
- Standardized error contract
Use Bean Validation annotations like:
@NotBlank@NotNull@Email@Min@Max@Pattern
Example
public class UserRequest {
@NotBlank
private String name;
@Email
private String email;
}
Spring automatically throws a validation exception if validation fails.
This exception occurs when a request body annotated with @Valid fails validation.
Example
@PostMapping
public User save(@Valid @RequestBody UserRequest request) {
}
Handler
@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<Map<String,String>> handleValidation( MethodArgumentNotValidException ex) {
Map<String,String> errors = new HashMap<>();
ex.getBindingResult()
.getFieldErrors()
.forEach(error ->
errors.put(error.getField(),
error.getDefaultMessage()));
return ResponseEntity.badRequest().body(errors);
}
Example Response
{
"email": "must be a valid email",
"name": "must not be blank"
}
Interview Tip: This is one of the most frequently asked Spring Boot exception questions.
It occurs when validation fails for:
- PathVariable
- RequestParam
- Method parameters
Example
@GetMapping("/users/{id}")public User getUser(
@PathVariable
@Min(1)
Long id) {
}
Handler
@ExceptionHandler(ConstraintViolationException.class)public ResponseEntity<String> handle( ConstraintViolationException ex) {
return ResponseEntity.badRequest()
.body(ex.getMessage());
}
J. Transactions & Exceptions
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
No.
By default,
Spring rolls back only RuntimeException and Error.
Checked exceptions do not trigger rollback automatically.
Example
@Transactional
public void save() throws IOException {
repository.save(user);
throw new IOException();
}
Result
Data is committed.
Interview One-liner: Checked exceptions do not cause rollback unless explicitly configured.
Yes.
Example
@Transactional
public void save() {
repository.save(user);
throw new RuntimeException();
}
Transaction
Rollback
Interview Tip: This is the default behavior of @Transactional.
Default Rules
Rollback occurs for:
- RuntimeException
- Error
No rollback for:
- Checked Exception
- Table
rollbackFor tells Spring to roll back even for checked exceptions.
Example
@Transactional(
rollbackFor = IOException.class
)
public void save()throws IOException{
repository.save(user);
throw new IOException();
}
Now
Rollback occurs.
Interview One-liner: rollbackFor extends rollback behavior to checked exceptions.
noRollbackFor prevents rollback even when a runtime exception occurs.
Example
@Transactional(
noRollbackFor = IllegalArgumentException.class
)
public void save() {
repository.save(user);
throw new IllegalArgumentException();
}
Transaction
Commit
Interview Tip: Useful when the exception is expected and should not undo the transaction.
K. Production Scenarios
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
A production-ready REST API should follow these practices:
- Use custom exceptions for business rules.
- Handle exceptions globally using @RestControllerAdvice.
- Return consistent JSON error responses.
Map exceptions to proper HTTP status codes.
Log exceptions with context.
Never expose internal implementation details.
Typical flow
Controller
↓
Service
↓
Repository
↓ Exception ↓
Global Exception Handler
↓
Standard JSON Response
Common Mapping
Interview Tip: Always choose the HTTP status code that best reflects the error rather than returning 500 for every failure.
No.
Stack traces reveal internal implementation details such as:
- Package names
- Database information
- Server structure
- Security-sensitive details
- Bad Response
{
"exception":"NullPointerException",
"stackTrace":"...."
}
Good Response
{
"status":404,
"message":"User not found"
}
Interview One-liner: Log the stack trace internally, but return only safe, user-friendly error messages to clients.
Use a logging framework such as SLF4J with Logback (the default in Spring Boot).
Example
private static final Logger logger =
LoggerFactory.getLogger(UserService.class);
try {
repository.save(user);
} catch (Exception ex) {
logger.error("Failed to save user. userId={}", user.getId(), ex);
throw ex;
}
Best Practices
Log with appropriate levels (ERROR, WARN, INFO).
Include business context (user ID, order ID, request ID).
Avoid logging sensitive information such as passwords or tokens.
Use correlation IDs or trace IDs in distributed systems.
Wrap external API calls in service classes.
Use:
- Timeout configuration
- Retry (Spring Retry or Resilience4j)
- Circuit Breaker (Resilience4j)
- Fallback methods
- Custom exceptions
Example
try {
paymentClient.process(payment);
} catch (FeignException ex) {
throw new PaymentServiceException(
"Payment service unavailable", ex);
}
Interview Tip: Never expose raw exceptions from third-party libraries like FeignException or WebClientResponseException directly to API consumers.
Let Spring translate low-level database exceptions into its DataAccessException hierarchy.
Example
try {
repository.save(user);
} catch (DataAccessException ex) {
throw new DatabaseException(
"Unable to save user", ex);
}
Examples
- DuplicateKeyException
- DataIntegrityViolationException
- CannotAcquireLockException
- OptimisticLockingFailureException
Interview Tip: Avoid exposing SQL errors directly. Translate them into meaningful business exceptions.
This is called Exception Translation.
Example
try {
repository.findById(id);
} catch (DataAccessException ex) {
throw new UserServiceException(
"Unable to fetch user details", ex);
}
Benefits
- Hides implementation details.
- Provides meaningful business errors.
- Preserves the original cause for debugging.
- Makes service APIs cleaner.
Use Global Exception Handling with @RestControllerAdvice.
Without Global Handling
@GetMapping("/{id}")public User getUser(Long id) {
try {
return service.get(id);
} catch(Exception e) {
// repeated code
}
}
With Global Handling
@GetMapping("/{id}")public User getUser(Long id) {
return service.get(id);
}
All exceptions are handled centrally.
Interview One-liner: Keep controllers focused on business logic and move exception handling into a global @RestControllerAdvice.
L. Frequently Asked Scenario Questions
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Java designers classified exceptions into two categories:
Checked Exceptions represent conditions that are recoverable and expected, so the compiler forces the developer to handle them.
Runtime Exceptions usually indicate programming mistakes, so forcing developers to catch them would lead to unnecessary boilerplate.
Examples
- Checked
- IOException
- SQLException
These are external failures that the application may recover from.
Unchecked
NullPointerException
ArithmeticException
ArrayIndexOutOfBoundsException
These indicate bugs in the code.
Interview One-liner: Checked exceptions represent recoverable conditions, whereas RuntimeExceptions usually represent programming errors.
Create a checked exception when:
- The caller can reasonably recover from the failure.
- The caller must decide how to handle the problem.
Examples
File processing
Payment gateway acknowledgment
Report generation
External system integration requiring retry
Example
public void importFile() throws FileImportException
The caller may:
- Retry
- Ask user for another file
- Cancel operation
Interview Tip: Checked exceptions are rare in modern Spring Boot applications because they increase coupling between layers.
Create a runtime exception for:
- Business rule violations
- Validation failures
- Invalid requests
- Illegal application state
Examples
- ResourceNotFoundException
- DuplicateUserException
- InvalidOrderStateException
- ValidationException
Spring Boot applications mostly use RuntimeException because they integrate naturally with global exception handling.
Interview One-liner: Business exceptions in Spring Boot generally extend RuntimeException.
Because a NullPointerException indicates a bug in the code, not an external failure.
Example
String name = null;
name.length();
Recovering from this at runtime is usually not meaningful; the fix is to correct the code.
Interview Tip: The compiler cannot reliably predict all null values at compile time, so Java treats it as a runtime issue.
An IOException usually results from external conditions beyond the application’s control:
- File missing
- Permission denied
- Disk full
- Network issue
The application may recover by:
- Asking for another file
- Retrying
- Showing an error to the user
- Therefore Java requires handling.
Interview One-liner: IOException is checked because it represents recoverable I/O failures.
Problems
Hides the actual exception type.
Makes debugging harder.
Can swallow unexpected exceptions.
Violates clean architecture.
Bad
catch(Exception e) {}
Better
catch(IOException e) {}
Interview Tip: Catch only the exceptions you can actually handle.
Error represents serious JVM failures.
Examples
- OutOfMemoryError
- StackOverflowError
- InternalError
Applications generally cannot recover from these conditions.
Interview One-liner: Errors indicate JVM-level failures, not business failures.
A production-ready microservice should follow these principles:
Global Exception Handler
- Use
@RestControllerAdvice
Custom Business Exceptions
Examples
- ResourceNotFoundException
- ValidationException
- PaymentFailedException
Standard API Response
Every service returns the same JSON format.
Example
{
"timestamp":"",
"status":404,
"error":"Not Found",
"message":"User not found",
"path":"/users/10"
}
Proper HTTP Status Codes
400
404
409
500
Logging
Log
requestId
traceId
userId
Exception Translation
Convert
SQLException
↓
DatabaseException
or
FeignException
↓
PaymentServiceException
Resilience
Handle external failures using
Retry
Circuit Breaker
Timeout
Fallback
using Resilience4j.
Interview One-liner: In microservices, I centralize exception handling, standardize API responses, translate low-level exceptions into business exceptions, and use resilience patterns for external service failures.
My production strategy is:
- Custom Runtime Exceptions
- Global Exception Handler
- Standard API Error Response
- Proper HTTP Status Codes
- SLF4J Logging
- Exception Translation
- Bean Validation
- No duplicate try-catch blocks
- Flow
- Controller
- ↓
- Service
- ↓
- Repository
- ↓
- Exception
- ↓
@RestControllerAdvice
↓
JSON Response
Interview Tip: This is an excellent answer for senior-level interviews.
Create a common response object.
Example
public class ApiError {
LocalDateTime timestamp;
int status;
String error;
String message;
String path;
}
Every exception returns this object.
Benefits
- Frontend consistency
- Easier debugging
- API contract remains stable
A good exception should contain:
- Meaningful message
- Business context
- Original cause
- Error code (optional)
- Timestamp (response)
- HTTP Status (API)
- Bad
- Exception
- Good
- Order 5001 cannot be cancelled because it has already been shipped.
Interview Tip: Do not include passwords, SQL queries, or stack traces in client-facing messages.
I follow these steps:
- Check application logs.
- Search using traceId/requestId.
- Review the stack trace.
- Reproduce the issue locally.
- Check database records.
- Check external API logs.
- Review monitoring tools like Grafana/Prometheus.
- Add missing logs if required.
Interview One-liner: I correlate logs using trace IDs, analyze the stack trace, reproduce the issue, and verify dependent systems before applying a fix.
Exception chaining means wrapping one exception inside another while preserving the original cause.
Example
try {
repository.save(user);
} catch(SQLException e) {
throw new DatabaseException(
"Unable to save user", e);
}
Original exception
e
is preserved.
Retrieve
exception.getCause();
Benefits
- Better debugging
- Original stack trace preserved
- Cleaner architecture
Suppressed exceptions occur in try-with-resources when:
- The try block throws an exception.
- The resource’s close() method also throws an exception.
The exception from close() is stored as a suppressed exception instead of replacing the original one.
Retrieve using
exception.getSuppressed();
Interview Tip: Suppressed exceptions preserve all failure information without hiding the primary exception.
If finally throws an exception:
- It overrides any exception or return from the try or catch block.
- The original exception may be lost unless preserved.
Example
try {
throw new IOException();
} finally{
throw new RuntimeException();
}
Result
RuntimeException
The IOException is hidden.
Interview One-liner: Avoid throwing exceptions from finally because they can hide the original failure.
M. Coding Questions
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
public class ResourceNotFoundException extends RuntimeException{
public ResourceNotFoundException(String message) {
super(message);
}
}
Usage
throw new ResourceNotFoundException(
"User not found");
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(
ResourceNotFoundException.class)
public ResponseEntity<ApiError>
handle(ResourceNotFoundException ex) {
ApiError error = new ApiError(
LocalDateTime.now(),
404,
"Not Found",
ex.getMessage(),
"/users");
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(error);
}
}
try(BufferedReader reader =
new BufferedReader(
new FileReader("test.txt"))) {
System.out.println(reader.readLine());
} catch(IOException e) {
e.printStackTrace();
}
public class ApiError {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}
Example Response
{
"timestamp":"2026-07-26T10:30",
"status":404,
"error":"Not Found",
"message":"User not found",
"path":"/users/1"
}
public class Demo {
static void c() {
int x = 10/0;
}
static void b() {
c();
}
static void a() {
b();
}
public static void main(String[] args) {
try {
a();
} catch(Exception e) {
System.out.println("Handled");
}
}
}
Output
Handled
try {
int x = 10/0;
} catch(ArithmeticException e) {
System.out.println("Arithmetic Error");
} catch(Exception e) {
System.out.println("General Error");
}
Always keep specific catch blocks before general ones.
public class ValidationException extends RuntimeException{
public ValidationException(String message) {
super(message);
}
}
Usage
if(name.isBlank()) {
throw new ValidationException(
"Name is required");
}
try {
repository.save(user);
} catch(SQLException e) {
throw new DatabaseException(
"Unable to save user", e);
}
This preserves the original cause while exposing a business-friendly exception.
public class Demo {
public static void main(String[] args) {
try {
return;
} finally{
System.out.println("Finally Executed");
}
}
}
Output
Finally Executed
The finally block executes before the method actually returns.
Architecture
Client
│
▼
REST Controller
│
▼
Service
│
▼
Repository
│
Exception Thrown
│
▼
@RestControllerAdvice
│
▼
@ExceptionHandler
│
▼
ApiError Response
│
▼
HTTP 400 / 404 / 409 / 500
Components
Custom Exceptions
ResourceNotFoundException
ValidationException
DuplicateResourceException
Global Exception Handler
@RestControllerAdvice@ExceptionHandler
Standard Error Response
timestamp
status
error
message
path
Validation Handling
MethodArgumentNotValidException
ConstraintViolationException
Logging
SLF4J + Logback
Trace ID / Request ID
Business context
Exception Translation
SQLException → DatabaseException
FeignException → PaymentServiceException