← Back to Questions
Java

What are best practices for exception handling?

Learn What are best practices for exception handling? with simple explanations, real-time examples, interview tips and practical use cases.

What are Best Practices for Exception Handling in Java?

Exception handling best practices in Java are guidelines used to handle errors safely, clearly, and professionally without crashing the application.

In simple words:

Good exception handling makes Java applications reliable, readable, secure, and production-ready.


Why Exception Handling Best Practices are Important?

Poor exception handling can cause:

  • Application crashes
  • Hidden bugs
  • Security leaks
  • Resource leaks
  • Wrong API responses
  • Difficult debugging
  • Production downtime

Exception Handling Best Practices Overview


Risky Code

      |
      v

Specific Exception Handling

      |
      v

Proper Logging

      |
      v

Resource Cleanup

      |
      v

Meaningful Response

      |
      v

Stable Application


1. Handle Specific Exceptions

Always catch specific exceptions instead of catching generic Exception everywhere.

Bad Example

try {

    processPayment();

}
catch(Exception e) {

    System.out.println("Error");

}

Good Example

try {

    processPayment();

}
catch(PaymentFailedException e) {

    log.error("Payment failed", e);

}
catch(InsufficientBalanceException e) {

    log.warn("Insufficient balance", e);

}

Specific exceptions make code easier to debug and maintain.


2. Never Use Empty catch Blocks

Empty catch blocks hide errors and make production issues very difficult to identify.

Bad Example

try {

    saveUser();

}
catch(Exception e) {

}

Good Example

try {

    saveUser();

}
catch(Exception e) {

    log.error("User save failed", e);

}

3. Use Meaningful Exception Messages

Exception messages should clearly explain what failed.

Bad Example

throw new RuntimeException("Error");

Good Example

throw new UserNotFoundException(
    "User not found for id: " + userId
);

4. Do Not Expose Internal Details to Users

Never expose database errors, stack traces, server paths, or sensitive system details in API responses.

Bad API Response

SQLSyntaxErrorException:
Table payment_txn not found

Good API Response

{
  "message": "Payment processing failed. Please try again later."
}

5. Log Exceptions Properly

Logging helps developers debug production issues.

Good Example

log.error(
    "Order creation failed for userId: {}",
    userId,
    exception
);

Always include useful context like userId, orderId, transactionId, or requestId where safe.


6. Use try-with-resources for Resource Cleanup

Use try-with-resources for files, streams, database connections, sockets, and other AutoCloseable resources.

Good Example

try(
    BufferedReader reader =
        new BufferedReader(
            new FileReader("data.txt")
        )
) {

    return reader.readLine();

}

This automatically closes resources and prevents leaks.


7. Avoid Catching Throwable or Error

Do not catch Throwable or Error in normal application code.

Bad Example

catch(Throwable t) {

}

Errors like OutOfMemoryError and StackOverflowError are serious JVM-level problems and usually should not be handled like normal exceptions.


8. Use Custom Exceptions for Business Rules

Custom exceptions make business failures clear.

Example

if(balance < amount) {

    throw new InsufficientFundsException(
        "Insufficient balance for transaction"
    );

}

This is much better than throwing generic RuntimeException.


9. Do Not Use Exceptions for Normal Flow Control

Exceptions should represent exceptional situations, not regular business flow.

Bad Example

try {

    Integer.parseInt(input);

}
catch(Exception e) {

    // normal flow logic

}

Better Example

if(input.matches("\\d+")) {

    int value =
        Integer.parseInt(input);

}

10. Preserve the Original Exception Cause

When wrapping exceptions, always preserve the original cause.

Bad Example

throw new PaymentException(
    "Payment failed"
);

Good Example

throw new PaymentException(
    "Payment failed",
    exception
);

This keeps the original stack trace available for debugging.


11. Use Global Exception Handling in Spring Boot

In Spring Boot, use @RestControllerAdvice for centralized API error handling.

@RestControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(
        UserNotFoundException.class
    )
    public ResponseEntity<String> handleUserNotFound(
        UserNotFoundException ex
    ) {

        return ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body(ex.getMessage());

    }

}

12. Return Proper HTTP Status Codes

Scenario Recommended Status
Invalid input 400 Bad Request
Unauthorized user 401 Unauthorized
Access denied 403 Forbidden
Resource not found 404 Not Found
Conflict or duplicate data 409 Conflict
Server failure 500 Internal Server Error

13. Validate Inputs Early

Validate request data before business processing starts.

if(email == null || email.isBlank()) {

    throw new InvalidRequestException(
        "Email is required"
    );

}

14. Avoid Overusing Checked Exceptions

Use checked exceptions for recoverable problems like file, database, or network failures.

Use unchecked exceptions for programming errors or business rule violations.


15. Do Not Swallow Exceptions

Swallowing means catching an exception without logging, handling, or rethrowing it.

Bad Example

catch(IOException e) {

    return null;

}

Good Example

catch(IOException e) {

    log.error("File processing failed", e);

    throw new FileProcessingException(
        "Unable to process file",
        e
    );

}

16. Keep finally Blocks Simple

finally should be used only for cleanup, logging, or resource release.

Avoid placing business logic inside finally blocks.


17. Use Transaction Rollback Properly

In banking, payment, and order systems, exceptions should trigger rollback when required.

@Transactional
public void transferMoney() {

    debitAccount();

    creditAccount();

}

If an exception occurs, Spring can rollback the transaction automatically.


18. Add Request ID or Correlation ID in Logs

In microservices, every exception log should include requestId or correlationId.

log.error(
    "Order failed. requestId={}, orderId={}",
    requestId,
    orderId,
    exception
);

19. Do Not Print Stack Trace in Production Code

Bad Example

e.printStackTrace();

Good Example

log.error("Unexpected error occurred", e);

20. Create a Standard Error Response Format

Use consistent API error responses.

{
  "timestamp": "2026-05-23T10:30:00",
  "status": 404,
  "error": "USER_NOT_FOUND",
  "message": "User not found",
  "path": "/api/users/101"
}

Best Practices Summary Table

Best Practice Reason
Catch specific exceptions Improves debugging
Avoid empty catch blocks Prevents hidden bugs
Use custom exceptions Clear business errors
Use try-with-resources Prevents resource leaks
Log properly Helps production debugging
Preserve original cause Keeps root cause trace
Use global handlers Centralized API errors
Do not expose stack traces Improves security

Exception Handling in Banking Systems

Banking systems need strong exception handling for:

  • Transaction rollback
  • Payment failures
  • Fraud validation
  • Database failures
  • Audit logging
  • Duplicate transaction prevention

Transaction Started

      |
      v

Validation Fails

      |
      v

Custom Exception Thrown

      |
      v

Rollback Executed

      |
      v

Audit Log Created


Exception Handling in Spring Boot Microservices

Spring Boot microservices should use:

  • Custom exceptions
  • @RestControllerAdvice
  • Proper HTTP status codes
  • Request ID logging
  • Retry and fallback handling
  • Transaction rollback

REST Request

      |
      v

Service Layer Error

      |
      v

Custom Exception

      |
      v

Global Exception Handler

      |
      v

Clean API Response


Common Interview Mistakes

  • Catching generic Exception everywhere
  • Using empty catch blocks
  • Using e.printStackTrace() in production
  • Not preserving original exception cause
  • Returning sensitive stack traces to users
  • Using exceptions for normal business flow

Professional Interview Answer

Best practices for exception handling in Java include catching specific exceptions, avoiding empty catch blocks, using meaningful messages, creating custom exceptions for business errors, preserving the original exception cause, logging exceptions properly, using try-with-resources for resource cleanup, and avoiding exposure of internal stack traces to users. In Spring Boot applications, global exception handling using @RestControllerAdvice and @ExceptionHandler is recommended to return consistent API error responses. Enterprise applications, banking platforms, payment systems, REST APIs, distributed microservices, Hibernate systems, and cloud-native architectures require structured exception handling for transaction rollback, resource cleanup, retry mechanisms, fallback logic, audit logging, and production debugging. Good exception handling improves reliability, security, maintainability, observability, and user experience.


Frequently Asked Questions

What is the most important exception handling best practice?

Handle specific exceptions and never hide errors using empty catch blocks.

Should we catch Exception everywhere?

No, catch specific exceptions whenever possible.

Should stack traces be shown to users?

No, stack traces should be logged internally, not exposed to users.

Why use custom exceptions?

Custom exceptions make business errors meaningful and easier to handle.

What is best practice in Spring Boot?

Use @RestControllerAdvice for centralized exception handling.

Why this Java question is important?

This interview question helps candidates understand real-time backend development concepts, practical problem solving, coding fundamentals, system design basics and production-ready application behavior.

Practice this question carefully for Java backend roles, Spring Boot developer interviews, microservices interviews, company interviews and full-stack developer preparation.

About the Author

Naresh Kumar is a Senior Java Backend Engineer with experience building enterprise applications using Java, Spring Boot, Microservices, Docker, Kubernetes and Cloud technologies.