Comprehensive exception handling & error management interview questions and answers for Java.
Prepare for your next job interview with expert guidance.
try-with-resources (Java 7+) automatically closes resources that implement AutoCloseable interface. Resources are closed in reverse order of creation after try block completes or if exception occurs. Improves code by eliminating explicit finally blocks for resource cleanup, handling multiple resources, and properly managing suppressed exceptions. More concise and less error-prone than traditional try-finally.
Retry logic implementation: 1) Use loop with counter/timeout, 2) Exponential backoff between retries, 3) Catch specific exceptions that warrant retry, 4) Consider maximum retry attempts, 5) Log retry attempts, 6) Handle permanent failures appropriately. Important for distributed systems, network operations, and resilient applications.
Checked exceptions (extending Exception) must be declared in method signature or handled in try-catch blocks, representing recoverable conditions (e.g., IOException). Unchecked exceptions (extending RuntimeException) don't require explicit handling, representing programming errors (e.g., NullPointerException). Error class and its subclasses are also unchecked but represent unrecoverable conditions.
Exceptions in finalizers are caught by JVM and printed to error stream, but object finalization continues. Finalizer errors don't prevent garbage collection but may leave resources unclosed. Best practices: 1) Avoid finalizers, use try-with-resources, 2) Never throw exceptions from finalizers, 3) Handle all exceptions within finalizer, 4) Consider using Cleaner class (Java 9+) instead.
Suppressed exceptions occur when exception is thrown in try block and another occurs in finally or during resource closing (try-with-resources). Original exception is thrown with suppressed exceptions accessible via getSuppressed(). Java 7+ automatically handles suppressed exceptions in try-with-resources. Use addSuppressed() method to manually add suppressed exceptions.
Exception chaining (wrapping) preserves original exception as cause of new exception using initCause() or constructor with cause parameter. Used when: converting checked to unchecked exceptions, maintaining abstraction layers, preserving exception context. Access cause via getCause(). Helps in debugging by maintaining complete exception history.
Multi-catch (Java 7+) allows catching multiple exception types in single catch block using | operator. Restrictions: caught exception types must not have subclass relationship, exception parameter is implicitly final. Reduces code duplication when handling multiple exceptions same way. Type of catch parameter is intersection type of all alternatives.
Exception handling has overhead: stack trace creation, exception object creation, and unwinding stack. Best practices: 1) Use exceptions for exceptional conditions, not flow control, 2) Catch exceptions at appropriate level, 3) Avoid empty catch blocks, 4) Clear and reset exception state if rethrowing, 5) Consider exception pooling for high-performance systems.
Multi-threaded exception handling considerations: 1) Uncaught exceptions terminate thread but not JVM, use UncaughtExceptionHandler, 2) Exceptions don't propagate across thread boundaries, 3) ExecutorService tasks should handle exceptions or use Future.get(), 4) Consider thread pool behavior on exceptions, 5) Use appropriate synchronization when logging/handling exceptions.
REST exception handling considerations: 1) Map exceptions to appropriate HTTP status codes, 2) Provide meaningful error responses in consistent format, 3) Handle both application and framework exceptions, 4) Consider security in error messages, 5) Implement global exception handler, 6) Include correlation IDs for tracking, 7) Handle validation errors consistently. Balance between client usability and security.
try block contains code that might throw exceptions. catch blocks handle specific exceptions, ordered from most specific to most general. finally block always executes (except for System.exit() or JVM crash), used for cleanup. Execution order: try → catch (if exception occurs) → finally. Multiple catch blocks are allowed, but finally block is optional and must be last.
Custom exceptions are created by extending Exception (checked) or RuntimeException (unchecked). Best practices include: meaningful name ending with 'Exception', constructors for different initialization options, proper message and cause handling, and maintaining serialization compatibility. Use throw keyword to raise exception. Should include appropriate documentation and usage guidelines.
Overriding methods can't throw broader checked exceptions than overridden method (covariant exception types allowed). Can throw fewer or narrower checked exceptions. Unchecked exceptions aren't restricted. If superclass method doesn't throw exceptions, overriding method can only throw unchecked exceptions. This maintains LSP (Liskov Substitution Principle) and type safety.
throw is used to explicitly throw an exception within method (throw new Exception()). throws declares that method might throw exceptions, listed in method signature (throws Exception1, Exception2). throw is followed by exception instance, throws by exception types. throws required for checked exceptions not handled within method, throw used for actual exception creation.
Best practices include: 1) Handle specific exceptions before general ones, 2) Only catch exceptions you can handle meaningfully, 3) Document exceptions in Javadoc, 4) Include appropriate context in exception messages, 5) Use custom exceptions for domain-specific errors, 6) Clean up resources in finally block or use try-with-resources, 7) Log exceptions appropriately, 8) Don't swallow exceptions without good reason.
Lambda exceptions handling options: 1) Surround lambda body with try-catch, 2) Create wrapper method with try-catch, 3) Use Optional for potential nulls, 4) Use stream.filter() to skip problematic elements. For checked exceptions in streams, either wrap in unchecked exception or use specialized functional interfaces that can throw exceptions.
Stack trace provides execution path when exception occurred. Can be: 1) Accessed via getStackTrace(), 2) Filtered using setStackTrace(), 3) Truncated for performance, 4) Enhanced with custom information. Useful for debugging but capturing full trace has performance impact. Consider security implications when exposing stack traces in production.
Assertions (assert keyword) check program internal correctness, disabled by default (-ea to enable). Unlike exceptions, assertions: 1) Are development/testing tool, not error handling mechanism, 2) Should never have side effects, 3) Check internal invariants, not public API preconditions, 4) Can be completely removed by JVM. Use for debugging and testing, not production error handling.
Constructor exceptions: throw to indicate object creation failure, ensure proper cleanup, consider factory methods for alternative handling. Static initializer exceptions wrapped in ExceptionInInitializerError, can cause class initialization failure. Both cases require careful handling as they can affect object/class usability. Consider initialization-on-demand pattern for static initialization.
Logging and exception handling best practices: 1) Log at appropriate level (ERROR for exceptions), 2) Include contextual information, 3) Consider log volume in catch blocks, 4) Avoid logging and rethrowing unless adding context, 5) Use appropriate logging framework features (MDC, structured logging). Balance between debugging needs and performance/storage impact.