
Java is a cornerstone language in software development and remains a top choice for backend and enterprise solutions. Whether you're aspiring to become a Java developer, software engineer, or system architect, Stark.ai equips you with the tools to ace your Java job interviews with curated questions, real-world examples, and expert guidance.
`HashMap` is not synchronized and allows one `null` key and multiple `null` values, whereas `HashTable` is...
The `volatile` keyword in Java indicates that a variable's value will be modified by different threads. It ensures...
A deadlock in Java occurs when two or more threads are blocked forever, waiting for each other to release resources....
Variable shadowing occurs when a variable declared within a narrower scope has the same name as a variable in a...
Type inference (var keyword, introduced in Java 10) allows local variable types to be inferred by the compiler based...
Bitwise operators (&, |, ^, ~, <<, >>, >>>) manipulate individual bits in integer types. Common uses include: flags...
Numeric overflow occurs when a calculation exceeds the maximum value for a data type, wrapping around to the minimum...
String interning is the process of storing only one copy of each distinct string value in a pool. When strings are...
Floating-point arithmetic in Java can lead to precision issues due to binary representation limitations. Issues...
Labeled statements allow targeting specific outer loops/blocks with break/continue statements. While useful for...
The enhanced for-loop (for-each) internally uses Iterator/Array indexing. It's syntactic sugar that simplifies...
Compile-time constants (static final primitives/strings initialized with constant expressions) are inlined by the...
Method binding is the process of linking a method call to its definition. Static binding (compile-time) occurs with...
Singleton ensures a class has only one instance and provides global access to it. Implemented using private...
The Liskov Substitution Principle states that objects of a superclass should be replaceable with objects of its...
Object cloning creates a copy of an object using the clone() method from Object class. Classes must implement...
The diamond problem occurs in multiple inheritance when a class inherits from two classes that have a common...
Sealed classes (Java 17+) restrict which classes can inherit from them using 'permits' clause. They provide more...
Method dispatch determines which method implementation to call. For overloaded methods, selection is based on...
SOLID principles are: Single Responsibility (classes have one reason to change), Open-Closed (open for extension,...
Cohesion measures how strongly related and focused the responsibilities of a class are. Coupling measures the degree...
ConcurrentHashMap uses segment-level locking (pre-Java 8) or node-level locking (Java 8+) allowing multiple threads...
NavigableMap extends SortedMap to provide navigation methods: floorKey, ceilingKey, higherKey, lowerKey, etc....
Load factor determines when HashMap resizes (default 0.75). Lower value means less collisions but more memory,...
WeakHashMap allows keys to be garbage collected when no strong references exist. Entry is removed automatically...
BlockingQueue adds blocking operations to Queue: put() blocks when full, take() blocks when empty. Implementations...
Collections.sort() uses modified mergesort (Timsort since Java 7) for Objects, and quicksort for primitives. Time...
EnumSet is specialized Set implementation for enum types using bit vector internally. Offers constant time...
Concurrent collections (ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue) are thread-safe collections...
Spliterator (Java 8+) is used for traversing and partitioning elements, especially in parallel streams. Provides...
Suppressed exceptions occur when exception is thrown in try block and another occurs in finally or during resource...
Exception handling has overhead: stack trace creation, exception object creation, and unwinding stack. Best...
Multi-threaded exception handling considerations: 1) Uncaught exceptions terminate thread but not JVM, use...
Lambda exceptions handling options: 1) Surround lambda body with try-catch, 2) Create wrapper method with try-catch,...
Stack trace provides execution path when exception occurred. Can be: 1) Accessed via getStackTrace(), 2) Filtered...
Retry logic implementation: 1) Use loop with counter/timeout, 2) Exponential backoff between retries, 3) Catch...
Constructor exceptions: throw to indicate object creation failure, ensure proper cleanup, consider factory methods...
Exceptions in finalizers are caught by JVM and printed to error stream, but object finalization continues. Finalizer...
REST exception handling considerations: 1) Map exceptions to appropriate HTTP status codes, 2) Provide meaningful...
Major collectors: 1) Serial: single-thread, small heaps/applications, 2) Parallel: multiple threads, throughput...
Key parameters: 1) -Xmx: maximum heap size, 2) -Xms: initial heap size, 3) -XX:NewRatio: young/old generation ratio,...
G1 divides heap into equal-sized regions, each can be Eden, Survivor, Old. Works incrementally by collecting regions...
Diagnosis steps: 1) Analyze heap dumps (using tools like MAT), 2) Enable GC logging, 3) Monitor memory usage...
Escape analysis determines if object allocation can be eliminated. If object doesn't 'escape' method scope, JVM can:...
DirectByteBuffers allocate memory outside JVM heap (native memory) for better I/O performance. Implications: 1) Not...
Card table is data structure tracking references from old to young generation, optimizing garbage collection....
Object pooling reuses objects instead of creating new ones. Implementation: maintain pool of pre-allocated objects,...
Memory barriers ensure memory operation ordering in concurrent programs. Types: LoadLoad, StoreStore, LoadStore,...
Finalization delays object reclamation, requires two GC cycles. Reference processing (Soft/Weak/Phantom) adds...
Fork/Join framework (Java 7+) implements divide-and-conquer parallelism. Uses work-stealing algorithm: idle threads...
Atomic variables (AtomicInteger, AtomicReference, etc.) use Compare-And-Swap (CAS) operations for lock-free...
Happens-before relationship defines memory visibility rules between operations. Key relationships: 1) Program order...
ReentrantLock advantages over synchronized: 1) Trylock with timeout, 2) Interruptible locking, 3) Fair queueing...
Memory consistency errors occur when threads have inconsistent views of shared memory due to caching/reordering....
CompletableFuture extends Future with composition, chaining, combining operations. Features: 1) Async computation...
Phaser is flexible synchronization barrier supporting dynamic party registration. Features: 1) Multiple advance...
Lock striping divides single lock into multiple locks for different hashcode ranges (used in ConcurrentHashMap)....
Interruption is cooperative cancellation mechanism. Proper handling: 1) Check/clear interrupted status, 2) Throw...
Disruptor is high-performance inter-thread messaging library. Features: 1) Ring buffer for bounded queue, 2)...
Memory-mapped files (MappedByteBuffer) map file content directly to memory. Advantages: 1) Faster access for large...
FileChannel provides direct file access with features: 1) Memory-mapped files, 2) Direct buffer access, 3) File...
WatchService monitors directory for changes (create, modify, delete). Features: 1) Asynchronous notification, 2)...
Strategies: 1) Memory-mapped files for random access, 2) Buffered streams for sequential access, 3) Stream API for...
AsynchChannel enables non-blocking I/O operations. Benefits: 1) Improved scalability, 2) Better resource...
Custom serialization through private readObject()/writeObject() methods. Uses: 1) Control serialization format, 2)...
FileVisitor interface enables traversal of file trees. Methods: preVisitDirectory(), visitFile(), visitFileFailed(),...
File locking through FileChannel: shared (read) or exclusive (write) locks. Considerations: 1) Lock granularity, 2)...
RandomAccessFile: traditional API, synchronized methods, simpler interface. FileChannel: modern API, better...
Type erasure can cause method signature conflicts: List<String> and List<Integer> become same signature after...
Reifiable types maintain runtime information: primitives, non-generic types, raw types, unbounded wildcards....
Generic singleton challenges: 1) Type parameter not available for static methods/fields, 2) Multiple type parameters...
Generic type inheritance rules: 1) Box<Integer> not subtype of Box<Number> even if Integer extends Number, 2)...
Cannot create arrays of generic types due to type erasure. Workarounds: 1) Create Object array and cast, 2) Use...
Type tokens pass Class<T> objects to maintain runtime type information. Uses: 1) Generic factory methods, 2)...
Recursive type bound: <T extends Comparable<T>>. Uses: 1) Implementing comparable types, 2) Builder pattern with...
Variance handled through wildcards: covariance (? extends T), contravariance (? super T), invariance (T). Use cases:...
Heap pollution: variable of parameterized type refers to object not of that type. Causes: 1) Mixing raw and generic...
Reflection with generics challenges: 1) Type erasure limits runtime information, 2) Getting/setting generic types,...
Large object handling: 1) Use streaming methods (setBlob/setClob) for writing, 2) Stream in chunks when reading, 3)...
Isolation levels: READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE. Each level addresses different...
HikariCP implementation: 1) Configure HikariConfig with pool properties, 2) Create HikariDataSource, 3) Manage...
Database vendor handling: 1) Use vendor-neutral SQL, 2) Abstract vendor-specific code, 3) Use DatabaseMetaData for...
Connection retry/failover: 1) Implement retry logic with exponential backoff, 2) Handle different failure types...
Savepoints create points within transaction to roll back to, without rolling back entire transaction. Usage: 1)...
Performance optimization: 1) Use connection pooling, 2) Batch updates for bulk operations, 3) Appropriate fetch size...
Connection validation: 1) Test-on-borrow/return in connection pool, 2) Validation query configuration, 3) Connection...
`HashMap` is not synchronized and allows one `null` key and multiple `null` values, whereas `HashTable` is synchronized (thread-safe) and doesn't allow `null` keys or values.
The `volatile` keyword in Java indicates that a variable's value will be modified by different threads. It ensures visibility and ordering of changes made to the variable across threads, preventing caching of variable values by threads.
A deadlock in Java occurs when two or more threads are blocked forever, waiting for each other to release resources. Deadlocks occur when threads acquire locks in different orders. Avoiding deadlocks requires careful design of locking mechanisms.
Variable shadowing occurs when a variable declared within a narrower scope has the same name as a variable in a wider scope, temporarily hiding the outer variable. This can happen with local variables shadowing instance variables, or parameters shadowing class fields. It can lead to confusion and bugs if not properly managed using 'this' keyword or better naming.
Type inference (var keyword, introduced in Java 10) allows local variable types to be inferred by the compiler based on the initialization value. Limitations include: must be initialized at declaration, can't be used for fields/parameters/return types, can't be initialized to null, and type must be clearly inferrable. It improves code readability while maintaining type safety.
Bitwise operators (&, |, ^, ~, <<, >>, >>>) manipulate individual bits in integer types. Common uses include: flags and permissions (using bitmasks), optimization for multiplication/division by powers of 2, low-level data manipulation, and memory-efficient data storage. Understanding two's complement representation is crucial for proper usage.
Numeric overflow occurs when a calculation exceeds the maximum value for a data type, wrapping around to the minimum value (and vice versa for underflow). Java doesn't automatically detect these conditions. They should be handled by: using larger data types, checking bounds before operations, using Math.addExact() for checked arithmetic, or BigInteger/BigDecimal for precise calculations.
String interning is the process of storing only one copy of each distinct string value in a pool. When strings are interned (using String.intern()), identical string literals reference the same memory location. It's useful for memory optimization when dealing with many duplicate strings, but should be used carefully as interning has overhead and can impact garbage collection.
Floating-point arithmetic in Java can lead to precision issues due to binary representation limitations. Issues include: inexact decimal representations, rounding errors accumulation, and comparison problems. For precise decimal calculations, use BigDecimal. Special values like NaN and Infinity need careful handling. Understanding IEEE 754 standard helps in managing these issues.
Labeled statements allow targeting specific outer loops/blocks with break/continue statements. While useful for breaking out of nested loops or controlling complex flow, they should be used sparingly as they can make code harder to understand. Better alternatives often include extracting methods or restructuring logic to avoid deep nesting.
The enhanced for-loop (for-each) internally uses Iterator/Array indexing. It's syntactic sugar that simplifies iteration but has limitations: can't modify collection size during iteration, can't track index position, can't iterate multiple collections simultaneously, and requires Iterable implementation. Understanding these limitations helps choose between traditional and enhanced for-loops.
Compile-time constants (static final primitives/strings initialized with constant expressions) are inlined by the compiler, improving performance by eliminating field access. They must be initialized at declaration and can't be changed. This optimization affects class loading and versioning - changes require recompilation of dependent classes.
Method binding is the process of linking a method call to its definition. Static binding (compile-time) occurs with private, static, and final methods where the compiler knows which method to call. Dynamic binding (runtime) occurs with virtual methods that can be overridden, where the actual object type determines which method is called. Dynamic binding enables polymorphism in Java.
Singleton ensures a class has only one instance and provides global access to it. Implemented using private constructor and static instance method. Limitations include: making unit testing difficult, potentially violating single responsibility principle, creating global state, and threading issues. Modern alternatives include dependency injection and proper object lifecycle management.
The Liskov Substitution Principle states that objects of a superclass should be replaceable with objects of its subclasses without affecting program correctness. In Java, this means subclass methods should: accept parameters of same/wider types, return same/narrower types, throw same/fewer exceptions, and maintain superclass invariants. Violations indicate poor inheritance hierarchy design.
Object cloning creates a copy of an object using the clone() method from Object class. Classes must implement Cloneable interface and override clone(). Shallow cloning copies object references, while deep cloning creates new instances of referenced objects. Considerations include: handling circular references, maintaining invariants, and dealing with final fields. Alternative approaches include copy constructors or static factory methods.
The diamond problem occurs in multiple inheritance when a class inherits from two classes that have a common ancestor, creating ambiguity about which version of inherited methods to use. Java avoids this by not supporting multiple class inheritance, only allowing multiple interface inheritance. With interfaces, the most specific default method implementation is used, or compilation fails if ambiguous.
Sealed classes (Java 17+) restrict which classes can inherit from them using 'permits' clause. They provide more control over class hierarchy, ensuring only intended subclasses exist. Subclasses must be declared 'final', 'sealed', or 'non-sealed'. Useful for domain modeling, API design, and pattern matching exhaustiveness checking.
Method dispatch determines which method implementation to call. For overloaded methods, selection is based on compile-time types of arguments (static dispatch). For overridden methods, selection is based on runtime type of object (dynamic dispatch). Understanding this is crucial for polymorphic behavior and avoiding subtle bugs with method resolution.
SOLID principles are: Single Responsibility (classes have one reason to change), Open-Closed (open for extension, closed for modification), Liskov Substitution (subtypes must be substitutable), Interface Segregation (clients shouldn't depend on unused methods), Dependency Inversion (depend on abstractions). Implementation involves proper interface design, inheritance hierarchies, and dependency management.
Cohesion measures how strongly related and focused the responsibilities of a class are. Coupling measures the degree of interdependence between classes. High cohesion (class does one thing well) and loose coupling (minimal dependencies) are desired. Achieved through proper encapsulation, interface-based design, and dependency injection. Important for maintainability and reusability.
ConcurrentHashMap uses segment-level locking (pre-Java 8) or node-level locking (Java 8+) allowing multiple threads to write simultaneously to different segments/nodes. Synchronized HashMap locks the entire map for each operation. ConcurrentHashMap provides better scalability, doesn't block reads, and offers atomic operations like putIfAbsent(). It never throws ConcurrentModificationException during iteration.
NavigableMap extends SortedMap to provide navigation methods: floorKey, ceilingKey, higherKey, lowerKey, etc. TreeMap implements it. Use cases include: range queries, finding closest matches, maintaining ordered key-value pairs with efficient navigation. Useful for applications like price ranges, time series data, or any ordered mapping requiring nearest-match queries.
Load factor determines when HashMap resizes (default 0.75). Lower value means less collisions but more memory, higher means better memory usage but more collisions. Resize operation is expensive (O(n)). Change default when: 1) Memory critical (increase), 2) Many collisions expected (decrease), 3) Performance critical with known size (adjust initial capacity instead).
WeakHashMap allows keys to be garbage collected when no strong references exist. Entry is removed automatically during next operation. Use cases: 1) Implementing caches that shouldn't prevent garbage collection, 2) Storing metadata about objects without memory leaks, 3) Maintaining mappings that shouldn't affect object lifecycle. Important for memory management in long-running applications.
BlockingQueue adds blocking operations to Queue: put() blocks when full, take() blocks when empty. Implementations (ArrayBlockingQueue, LinkedBlockingQueue) are thread-safe. Used in producer-consumer pattern where producers add items (blocking if full) and consumers remove items (blocking if empty). Provides built-in synchronization and eliminates need for explicit coordination.
Collections.sort() uses modified mergesort (Timsort since Java 7) for Objects, and quicksort for primitives. Time complexity O(n log n), space complexity O(n) for objects (due to merge sort's need for temporary array), O(log n) for primitives. Stable sort for objects, unstable for primitives. Elements must be Comparable or a Comparator must be provided.
EnumSet is specialized Set implementation for enum types using bit vector internally. Offers constant time operations, very memory efficient (one long per 64 enum constants). All operations are thread-safe due to atomic bit operations. Can't use with null values. Preferred over HashSet when working with enums due to superior performance and memory usage.
Concurrent collections (ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue) are thread-safe collections designed for concurrent access. Use when: 1) Multiple threads access collection, 2) Need better scalability than synchronized collections, 3) Want to avoid explicit synchronization. Trade-offs include slightly lower single-thread performance and possibly inconsistent iterations.
Spliterator (Java 8+) is used for traversing and partitioning elements, especially in parallel streams. Provides estimates of size, characteristics (ORDERED, SORTED, etc.), and splitting capabilities. Each collection provides specialized implementation optimized for its structure. Important for parallel processing and stream operations performance.
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 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.
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.
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.
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.
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.
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.
Major collectors: 1) Serial: single-thread, small heaps/applications, 2) Parallel: multiple threads, throughput priority, 3) G1: large heaps, balanced latency/throughput, default since Java 9, 4) ZGC: ultra-low latency, large heaps, 5) Shenandoah: similar to ZGC, different implementation. Choice depends on application requirements: latency, throughput, heap size, and available resources.
Key parameters: 1) -Xmx: maximum heap size, 2) -Xms: initial heap size, 3) -XX:NewRatio: young/old generation ratio, 4) -XX:SurvivorRatio: Eden/Survivor space ratio, 5) -XX:MetaspaceSize: Metaspace size. Best practices: set -Xms=-Xmx to avoid resizing, tune generation sizes based on object lifetime patterns, monitor GC logs for optimization.
G1 divides heap into equal-sized regions, each can be Eden, Survivor, Old. Works incrementally by collecting regions with most garbage first. Features: predictable pause times, concurrent marking, automatic region sizing, mixed collections. Advantages: reduced fragmentation, better predictability, suitable for large heaps. Requires more CPU resources than Parallel collector.
Diagnosis steps: 1) Analyze heap dumps (using tools like MAT), 2) Enable GC logging, 3) Monitor memory usage patterns, 4) Use profilers. Resolution: identify memory leaks, tune GC parameters, optimize object creation/retention, consider caching strategies, implement proper resource cleanup. Prevention: regular monitoring, load testing, code reviews focusing on memory usage.
Escape analysis determines if object allocation can be eliminated. If object doesn't 'escape' method scope, JVM can: 1) Allocate on stack instead of heap, 2) Perform scalar replacement (replace object with its fields), 3) Eliminate synchronization. These optimizations reduce GC pressure and improve performance. Enabled by default but requires proper conditions to trigger.
DirectByteBuffers allocate memory outside JVM heap (native memory) for better I/O performance. Implications: 1) Not subject to garbage collection, 2) Manual memory management needed, 3) Higher allocation/deallocation cost, 4) Risk of native memory leaks. Best used for long-lived buffers with significant I/O operations. Requires careful capacity planning and cleanup.
Card table is data structure tracking references from old to young generation, optimizing garbage collection. Divides heap into cards, marks cards when references updated (write barrier). Enables efficient young generation collection by scanning only relevant old generation areas. Critical for generational GC performance but adds slight overhead to reference updates.
Object pooling reuses objects instead of creating new ones. Implementation: maintain pool of pre-allocated objects, checkout/return methods, size limits, cleanup strategies. Appropriate for: expensive object creation, memory pressure reduction, connection management. Drawbacks: complexity, potential memory leaks, synchronization overhead. Modern JVM optimizations often make pooling unnecessary except for specific cases.
Memory barriers ensure memory operation ordering in concurrent programs. Types: LoadLoad, StoreStore, LoadStore, StoreLoad barriers. Impact performance by preventing CPU/compiler optimizations. Used in volatile variables, synchronization, concurrent collections. Understanding crucial for high-performance concurrent code. JMM (Java Memory Model) defines when barriers required.
Finalization delays object reclamation, requires two GC cycles. Reference processing (Soft/Weak/Phantom) adds overhead to GC. Both can cause memory leaks if not handled properly. Best practices: avoid finalization (use try-with-resources), carefully manage reference queues, understand reference processing order. Modern Java favors Cleaner over finalizers.
Fork/Join framework (Java 7+) implements divide-and-conquer parallelism. Uses work-stealing algorithm: idle threads steal tasks from busy ones. Components: ForkJoinPool, RecursiveTask (returns result), RecursiveAction (void). Best for CPU-intensive tasks that can be broken into smaller subtasks. Integrates with Stream API for parallel operations.
Atomic variables (AtomicInteger, AtomicReference, etc.) use Compare-And-Swap (CAS) operations for lock-free thread-safety. More efficient than synchronization for single variables. Use when: 1) Single variable updates need atomicity, 2) High contention scenarios, 3) Performance critical code. Limited to single variable operations, complex operations need different approaches.
Happens-before relationship defines memory visibility rules between operations. Key relationships: 1) Program order within thread, 2) Monitor lock/unlock, 3) volatile write/read, 4) Thread start/join. Essential for understanding when updates become visible between threads. Forms basis for Java Memory Model's consistency guarantees. Critical for writing correct concurrent code.
ReentrantLock advantages over synchronized: 1) Trylock with timeout, 2) Interruptible locking, 3) Fair queueing option, 4) Condition variables, 5) Non-block-structured locking. Disadvantages: explicit unlock required, more complex, easy to misuse. Use when advanced features needed, otherwise prefer synchronized for simplicity and automatic release.
Memory consistency errors occur when threads have inconsistent views of shared memory due to caching/reordering. Prevention: 1) Proper synchronization, 2) volatile for visibility, 3) final fields for initialization safety, 4) immutable objects, 5) happens-before relationships. Java Memory Model defines when updates must become visible. Tools like JCStress help detect issues.
CompletableFuture extends Future with composition, chaining, combining operations. Features: 1) Async computation pipelines, 2) Exception handling, 3) Timeout management, 4) Multiple completion stages, 5) Customizable execution. Simplifies async programming compared to callbacks or raw threads. Integrates with reactive programming patterns. Supports both async and sync operations.
Phaser is flexible synchronization barrier supporting dynamic party registration. Features: 1) Multiple advance phases, 2) Tree structure for scalability, 3) Arrival/completion monitoring, 4) Termination condition. Use cases: complex phased operations, dynamic thread groups, parallel decomposition. More flexible than CyclicBarrier/CountDownLatch but more complex.
Lock striping divides single lock into multiple locks for different hashcode ranges (used in ConcurrentHashMap). Lock coarsening combines adjacent synchronized blocks for performance. JVM optimizations reduce synchronization overhead. Trade-off between contention and overhead. Monitor JVM behavior to verify optimizations.
Interruption is cooperative cancellation mechanism. Proper handling: 1) Check/clear interrupted status, 2) Throw InterruptedException or restore flag, 3) Clean up resources, 4) Propagate interruption. Common in blocking operations, long-running tasks. Challenges: third-party code handling, partial results, cleanup. Design for cancellation from start.
Disruptor is high-performance inter-thread messaging library. Features: 1) Ring buffer for bounded queue, 2) Lock-free design, 3) Cache-friendly, 4) Multiple producer/consumer support. Use for high-throughput scenarios: financial trading, logging, event processing. Requires understanding of memory barriers, cache effects. Complex but highly efficient.
Memory-mapped files (MappedByteBuffer) map file content directly to memory. Advantages: 1) Faster access for large files, 2) OS-level optimization, 3) Direct memory access. Best for: large files, random access patterns, shared memory between processes. Limitations: file size constraints, resource management needed. Use FileChannel.map() to create mapping.
FileChannel provides direct file access with features: 1) Memory-mapped files, 2) Direct buffer access, 3) File locking, 4) Scatter/gather operations. NIO Buffers offer: 1) Direct memory access, 2) Bulk data operations, 3) Buffer pooling. Performance benefits from: reduced copying, system calls, and better memory usage. Suitable for high-performance I/O.
WatchService monitors directory for changes (create, modify, delete). Features: 1) Asynchronous notification, 2) Multiple directory monitoring, 3) Platform-specific optimizations. Implementation: register Path with WatchService, process WatchEvents in loop. Considerations: event coalescing, overflow handling, platform differences in sensitivity.
Strategies: 1) Memory-mapped files for random access, 2) Buffered streams for sequential access, 3) Stream API for processing, 4) Chunked reading/writing, 5) NIO channels for better performance. Consider: memory constraints, access patterns, threading model. Monitor memory usage, use profiling tools. Handle exceptions and cleanup properly.
AsynchChannel enables non-blocking I/O operations. Benefits: 1) Improved scalability, 2) Better resource utilization, 3) Reduced thread overhead. Completion handling through: CompletionHandler, Future, or callback. Suitable for: network I/O, many concurrent operations. Requires careful error handling and completion state management.
Custom serialization through private readObject()/writeObject() methods. Uses: 1) Control serialization format, 2) Handle sensitive data, 3) Maintain invariants, 4) Version compatibility. Implementation must handle: all fields, superclass state, validation, security. Consider readResolve()/writeReplace() for object replacement.
FileVisitor interface enables traversal of file trees. Methods: preVisitDirectory(), visitFile(), visitFileFailed(), postVisitDirectory(). Uses: recursive operations, filtering, attribute access. SimpleFileVisitor provides default implementations. Handle: cycles, permissions, errors. Consider performance for large directories.
File locking through FileChannel: shared (read) or exclusive (write) locks. Considerations: 1) Lock granularity, 2) Cross-process coordination, 3) Deadlock prevention, 4) Platform differences. FileLock must be released explicitly. Useful for concurrent access control. Remember: some platforms don't enforce mandatory locking.
RandomAccessFile: traditional API, synchronized methods, simpler interface. FileChannel: modern API, better performance, more features (memory mapping, locks, etc.). FileChannel advantages: non-blocking operations, bulk transfers, direct buffers. Choose based on: requirements, compatibility needs, performance needs.
Type erasure can cause method signature conflicts: List<String> and List<Integer> become same signature after erasure. Bridge methods generated for covariant returns in inheritance. Cannot overload methods differing only in generic type parameters. Solutions: use different method names, add additional parameters, use type tokens. Important for API design and inheritance hierarchies.
Reifiable types maintain runtime information: primitives, non-generic types, raw types, unbounded wildcards. Non-reifiable types lost during type erasure: generic types with parameters, bounded wildcards. Implications: can't create generic arrays, instanceof limitations, method overloading restrictions. Important for understanding generic type system limitations.
Generic singleton challenges: 1) Type parameter not available for static methods/fields, 2) Multiple type parameters create multiple instances. Solutions: 1) Generic static factory method, 2) Enum-based implementation, 3) Type token approach. Consider thread safety, serialization. Best practices: limit type parameters, document limitations, consider builder pattern alternative.
Generic type inheritance rules: 1) Box<Integer> not subtype of Box<Number> even if Integer extends Number, 2) Generic class inheritance uses type parameters in extends clause, 3) Raw types bypass generic type checking. Bridge methods handle inheritance with different type parameters. Consider bounded type parameters for hierarchies.
Cannot create arrays of generic types due to type erasure. Workarounds: 1) Create Object array and cast, 2) Use ArrayList instead, 3) Pass array creation to method parameter, 4) Use reflection (Array.newInstance). Each approach has trade-offs in type safety, performance, complexity. Consider collections as alternative to generic arrays.
Type tokens pass Class<T> objects to maintain runtime type information. Uses: 1) Generic factory methods, 2) Type-safe heterogeneous containers, 3) Reflection with generics. Implementation using Class.cast(), instanceof checks. Super type tokens (Neal Gafter) for preserving generic type information. Consider performance implications.
Recursive type bound: <T extends Comparable<T>>. Uses: 1) Implementing comparable types, 2) Builder pattern with fluent interface, 3) Self-referential generic types. Examples in natural ordering, comparable collections. Ensures type safety in comparison operations. Common in API design for fluent interfaces and type-safe comparisons.
Variance handled through wildcards: covariance (? extends T), contravariance (? super T), invariance (T). Use cases: 1) Collection APIs, 2) Method parameters, 3) Return types. Related to Liskov Substitution Principle. Important for API design and collection framework usage. Consider PECS principle for proper usage.
Heap pollution: variable of parameterized type refers to object not of that type. Causes: 1) Mixing raw and generic types, 2) Unchecked warnings, 3) Array covariance with generics. Prevention: 1) Address unchecked warnings, 2) Avoid raw types, 3) Use @SafeVarargs when appropriate. Can lead to runtime failures. Important for type safety.
Reflection with generics challenges: 1) Type erasure limits runtime information, 2) Getting/setting generic types, 3) Creating generic arrays. Solutions: Type tokens, ParameterizedType interface, GenericArrayType. Consider performance impact, maintainability. Useful for frameworks, dependency injection. Document reflection usage clearly.
Large object handling: 1) Use streaming methods (setBlob/setClob) for writing, 2) Stream in chunks when reading, 3) Consider performance and memory implications, 4) Properly close resources. Best practices: use try-with-resources, appropriate buffer sizes, transaction management. Consider file system storage for very large objects.
Isolation levels: READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE. Each level addresses different concurrency issues: dirty reads, non-repeatable reads, phantom reads. Higher isolation provides more consistency but reduces concurrency. Choose based on requirements: data consistency needs vs performance/scalability.
HikariCP implementation: 1) Configure HikariConfig with pool properties, 2) Create HikariDataSource, 3) Manage connection lifecycle. Key settings: maximum pool size, connection timeout, idle timeout, minimum idle. Best practices: proper sizing, connection testing, metrics monitoring. Popular choice due to performance and reliability.
Database vendor handling: 1) Use vendor-neutral SQL, 2) Abstract vendor-specific code, 3) Use DatabaseMetaData for feature detection, 4) Implement dialect patterns for SQL differences. Consider: pagination differences, data type mappings, feature support. Use database abstraction layers or JPA for better portability.
Connection retry/failover: 1) Implement retry logic with exponential backoff, 2) Handle different failure types appropriately, 3) Use connection pools with test-on-borrow, 4) Implement circuit breaker pattern. Consider: timeout settings, maximum retry attempts, failover nodes. Balance between availability and response time.
Savepoints create points within transaction to roll back to, without rolling back entire transaction. Usage: 1) Complex transactions with partial rollback needs, 2) Nested transaction-like behavior, 3) Error recovery within transaction. Considerations: performance impact, database support, proper release. Use sparingly due to complexity.
Performance optimization: 1) Use connection pooling, 2) Batch updates for bulk operations, 3) Appropriate fetch size for ResultSet, 4) Proper transaction boundaries, 5) Prepared statement caching, 6) Index usage awareness. Monitor: connection usage, query performance, resource utilization. Balance between performance and maintainability.
Connection validation: 1) Test-on-borrow/return in connection pool, 2) Validation query configuration, 3) Connection timeout settings, 4) Idle connection testing. Importance: preventing stale connections, ensuring reliability. Balance validation frequency with performance impact. Consider database-specific validation queries.
Solve Java coding challenges designed for real-world relevance.
Explore MoreUnderstand Java fundamentals like OOP, multithreading, and memory management.
Use platforms like Stark.ai to solve coding challenges.
Showcase your experience with Java applications in interviews.
Be ready to explain how Java helped you solve specific problems.
Join thousands of successful candidates who prepared with Stark.ai. Start practicing Java questions, mock interviews, and more to secure your dream role.
Start Preparing now