Skip to main content

Amazon Interview Java Interview Questions

Curated Amazon Interview-level Java interview questions for developers targeting amazon interview positions. 120 questions available.

Last updated:

Java Interview Questions & Answers

Skip to Questions

Welcome to our comprehensive collection of Java interview questions and answers. This page contains expertly curated interview questions covering all aspects of Java, from fundamental concepts to advanced topics. Whether you're preparing for an entry-level position or a senior role, you'll find questions tailored to your experience level.

Our Java interview questions are designed to help you:

  • Understand core concepts and best practices in Java
  • Prepare for technical interviews at all experience levels
  • Master both theoretical knowledge and practical application
  • Build confidence for your next Java interview

Each question includes detailed answers and explanations to help you understand not just what the answer is, but why it's correct. We cover topics ranging from basic Java concepts to advanced scenarios that you might encounter in senior-level interviews.

Use the filters below to find questions by difficulty level (Entry, Junior, Mid, Senior, Expert) or focus specifically on code challenges. Each question is carefully crafted to reflect real-world interview scenarios you'll encounter at top tech companies, startups, and MNCs.

Questions

120 questions
Q1:

What are the main features of Java?

Entry

Answer

Key Features:
• Object-Oriented
• Platform-Independent via JVM
• Robust memory management
• Multithreaded
• Secure via JVM sandboxing
Quick Summary: Java's main features: platform independence (write once, run anywhere via JVM), object-oriented, strongly typed, automatic memory management (garbage collection), multi-threading support, rich standard library, and robust exception handling. Java compiles to bytecode that runs on any JVM regardless of OS or hardware.
Q2:

What is the difference between JDK, JRE, and JVM?

Entry

Answer

JVM: Executes Java bytecode.
JRE: JVM + libraries needed to run Java apps.
JDK: JRE + tools for developing Java applications.
Quick Summary: JDK (Java Development Kit): full package for developing Java apps - includes compiler (javac), JRE, and dev tools. JRE (Java Runtime Environment): what end users need to run Java apps - includes JVM and standard libraries but no compiler. JVM (Java Virtual Machine): the engine that executes compiled bytecode. JDK contains JRE which contains JVM.
Q3:

What is the difference between Java and C++?

Entry

Answer

Java uses automatic garbage collection.
Java is platform-independent; C++ is platform-specific.
Java does not support direct pointers, improving security.
Quick Summary: Java vs C++: Java is interpreted (bytecode + JVM), C++ compiles to native machine code. Java has automatic garbage collection, C++ uses manual memory management. Java doesn't support multiple class inheritance (uses interfaces), C++ does. Java has no pointers (only references), C++ has full pointer arithmetic. Java is platform-independent, C++ is platform-specific by default.
Q4:

Explain object-oriented programming concepts in Java.

Entry

Answer

OOP principles:
• Encapsulation
• Inheritance
• Polymorphism
• Abstraction
Java applies these via classes, interfaces, and objects.
Quick Summary: Java OOP concepts: Encapsulation (bundle data and methods, control access via modifiers), Inheritance (a class extends another to reuse and extend behavior), Polymorphism (one interface, multiple implementations - method overriding at runtime), Abstraction (hide implementation details, expose only what's needed via abstract classes and interfaces).
Q5:

What is a class and an object in Java?

Entry

Answer

Class: Blueprint for creating objects.
Object: Instance of a class containing data and behavior.
Quick Summary: A class is a blueprint/template that defines fields (data) and methods (behavior). An object is an instance of a class - created with the new keyword. Example: class Car defines color, speed, and drive(). Each Car object is a separate instance with its own color and speed values but shares the same class methods.
Q6:

What are primitive and reference data types?

Entry

Answer

Primitive: Stores actual value (int, boolean, etc.).
Reference: Stores memory address of objects (arrays, strings, objects).
Quick Summary: Primitive types (int, double, boolean, char, byte, short, long, float) store values directly in memory - fast, no object overhead. Reference types (String, arrays, objects) store a reference (memory address) to an object on the heap. Primitives can't be null; reference types can. Primitives are passed by value; object references are also passed by value (the reference, not the object).
Q7:

What is the difference between method overloading and overriding?

Entry

Answer

Overloading: Same method name, different parameters.
Overriding: Subclass modifies inherited method.
Overloading = compile-time; overriding = runtime behavior.
Quick Summary: Overloading: same method name, different parameter types or count, resolved at compile time. Overriding: subclass provides a different implementation of a parent class method with the same signature, resolved at runtime (dynamic dispatch). Overloading is compile-time polymorphism; overriding is runtime polymorphism. Use @Override annotation to ensure you're actually overriding.
Q8:

What are constructors in Java?

Entry

Answer

Constructors initialize objects.
Can be default or parameterized.
Overloaded constructors offer multiple initialization ways.
Quick Summary: A constructor is a special method that initializes a new object. Same name as the class, no return type. Called automatically when you use new. If you don't define one, Java provides a default no-arg constructor. You can have multiple constructors (constructor overloading). Use this() to call another constructor in the same class.
Q9:

What is the difference between this and super keywords?

Entry

Answer

this: Refers to current instance.
super: Refers to parent class.
Used to call parent constructors and resolved naming conflicts.
Quick Summary: this refers to the current class instance - used to distinguish instance variables from local variables, or call other constructors (this()). super refers to the parent class - used to call parent class methods (super.method()), access parent fields (super.field), or call the parent constructor (super()) - which must be the first line in the child constructor.
Q10:

What are access modifiers in Java?

Entry

Answer

public: Accessible everywhere.
private: Inside class only.
protected: Same package + subclasses.
default: Same package.
Quick Summary: Access modifiers control visibility: private (only within the same class), default/package-private (no keyword - within the same package), protected (same package + subclasses), public (accessible everywhere). Rule of thumb: make fields private, methods public or package-private as needed. Use the most restrictive modifier that works for your use case.
Q11:

What is the difference between static and instance members?

Entry

Answer

Static: Belongs to class, shared by all objects.
Instance: Unique per object.
Static members accessed without creating object.
Quick Summary: Static members belong to the class, not instances. Static fields are shared across all instances. Static methods can be called without creating an object (Math.sqrt()). Instance members belong to each object individually - each instance has its own copy of instance fields. Static methods can't access instance fields (no "this" available).
Q12:

What is the difference between final, finally, and finalize?

Entry

Answer

final: Constant or non-overridable.
finally: Executes after try/catch.
finalize: Called before garbage collection.
Quick Summary: final: variable can't be reassigned, method can't be overridden, class can't be extended. finally: block in try-catch that always runs (even if exception thrown) - used for cleanup (closing resources). finalize(): method called by GC before collecting an object - deprecated in Java 9, don't rely on it. All three are completely different concepts that happen to sound similar.
Q13:

What is garbage collection in Java?

Entry

Answer

Automated memory cleanup removing unused objects.
Prevents memory leaks and improves performance.
Quick Summary: Java garbage collection automatically frees memory occupied by objects with no live references. The GC runs in the background, identifies unreachable objects, and reclaims their memory. You can't force GC (System.gc() is just a hint). Modern GC algorithms (G1, ZGC, Shenandoah) minimize pause times. Memory leaks happen when you keep references to objects you no longer need.
Q14:

What are Java packages and their benefits?

Entry

Answer

Packages group related classes.
Provide organization, modularity, and access control.
Prevents naming conflicts.
Quick Summary: Packages are namespaces that organize related classes. Benefits: avoid name collisions between classes in different libraries, control access (package-private visibility), and logical grouping makes code easier to navigate. Declare with "package com.example.model" at top of file. Import classes from other packages with "import". Java standard library uses java.util, java.io, java.lang etc.
Q15:

What is an interface and how is it different from an abstract class?

Entry

Answer

Interface: Only abstract methods (older Java).
Abstract class: Can have concrete methods and fields.
Interfaces support multiple inheritance.
Quick Summary: Interface: defines a contract (method signatures), no instance fields (only constants), a class can implement multiple interfaces, methods are public abstract by default (Java 8+ allows default and static methods). Abstract class: can have concrete methods and instance fields, single inheritance only, use when related classes share common implementation. Choose interface for capabilities, abstract class for shared base implementation.
Q16:

What are Java exceptions?

Entry

Answer

Exceptions represent runtime errors.
Checked exceptions must be handled.
Unchecked exceptions don't require mandatory handling.
Quick Summary: Exceptions are runtime errors that disrupt normal program flow. Checked exceptions (IOException, SQLException) must be caught or declared with throws - checked at compile time. Unchecked exceptions (RuntimeException, NullPointerException, ArrayIndexOutOfBoundsException) don't need to be explicitly handled. Use try-catch-finally to handle exceptions. Create custom exceptions by extending Exception or RuntimeException.
Q17:

What is the difference between == and equals()?

Entry

Answer

== compares references.
equals() compares values.
equals() can be overridden for custom comparison.
Quick Summary: == compares references (memory addresses) for objects - checks if two variables point to the same object. equals() compares content/value - should be overridden to define logical equality. "abc" == "abc" may be true (string pool) but new String("abc") == new String("abc") is false. Always use equals() to compare object values, use == only for primitives or reference identity checks.
Q18:

What are wrapper classes and autoboxing/unboxing?

Entry

Answer

Wrapper classes represent primitive types as objects.
Autoboxing: primitive ? wrapper.
Unboxing: wrapper ? primitive.
Quick Summary: Wrapper classes (Integer, Double, Boolean etc.) wrap primitive types as objects so they can be used in collections and generics. Autoboxing: automatic conversion from primitive to wrapper (int to Integer). Unboxing: automatic conversion from wrapper to primitive. Watch out: unboxing a null Integer throws NullPointerException. Autoboxing in loops can create many short-lived objects.
Q19:

What are Java generics and why are they used?

Entry

Answer

Generics provide type safety.
Prevent runtime casting errors.
Used in classes, methods, and collections.
Quick Summary: Generics allow you to write type-safe code that works with any type without casting. List instead of raw List. The compiler catches type mismatches at compile time. Type parameters are erased at runtime (type erasure) - the JVM sees raw types. Benefits: no need for explicit casting, compile-time type safety, reusable algorithms that work on any type.
Q20:

What are Java collections?

Entry

Answer

Collections store groups of objects.
Common types: List, Set, Map, Queue.
Provide efficient searching, sorting, and manipulation.
Quick Summary: Java Collections Framework provides reusable data structures. Core interfaces: List (ordered, allows duplicates), Set (no duplicates), Map (key-value pairs), Queue (FIFO), Deque (double-ended). Common implementations: ArrayList, LinkedList, HashSet, TreeSet, HashMap, TreeMap. Prefer List/Map/Set interfaces in variable types for flexibility. Use Collections utility class for sorting, searching, and synchronizing.
Q21:

What are Java 8 Lambda expressions?

Entry

Answer

Lambda expressions are anonymous functions used to implement functional interfaces.
They simplify collection processing, event handling, and reduce boilerplate.
Improve readability compared to anonymous inner classes.
Quick Summary: Lambda expressions are short anonymous functions. Syntax: (params) -> expression or (params) -> { statements }. Enables functional programming style. Used to implement functional interfaces (interfaces with one abstract method). Instead of anonymous inner class: Comparator c = (a, b) -> a.compareTo(b). Lambdas capture effectively final variables from the enclosing scope.
Q22:

Explain functional interfaces.

Entry

Answer

Functional interfaces have one abstract method (SAM).
Examples include Runnable, Callable, Comparator.
Marked with @FunctionalInterface and used with lambda expressions.
Quick Summary: Functional interfaces have exactly one abstract method (can have default and static methods). Annotate with @FunctionalInterface (optional but recommended). Built-in functional interfaces in java.util.function: Predicate (test, returns boolean), Function (apply, transforms T to R), Consumer (accept, takes T returns void), Supplier (get, returns T). Lambdas can be assigned to functional interfaces.
Q23:

What is the Streams API in Java?

Entry

Answer

Streams provide functional-style operations for processing data sequences.
Support map, filter, reduce, collect operations.
Work in sequential or parallel mode.
Quick Summary: Streams API processes collections declaratively. Pipeline: source (list.stream()) -> intermediate operations (filter, map, sorted) -> terminal operation (collect, count, forEach). Lazy evaluation - intermediate ops only run when terminal op is called. Supports method chaining. Parallel streams: list.parallelStream(). Different from java.io streams - these are for processing sequences of data.
Q24:

Difference between intermediate and terminal operations in Streams.

Entry

Answer

Intermediate operations are lazy and return streams (map, filter, sorted).
Terminal operations produce results (collect, forEach, reduce).
Pipeline allows chaining multiple intermediate operations.
Quick Summary: Intermediate operations are lazy - they don't execute until a terminal op is called and return a Stream. Examples: filter(), map(), flatMap(), sorted(), distinct(), limit(), peek(). Terminal operations trigger execution and produce a result or side effect. Examples: collect(), count(), forEach(), reduce(), findFirst(), anyMatch(), toList(). Only one terminal operation per stream pipeline.
Q25:

Explain Optional in Java.

Entry

Answer

Optional prevents null references by wrapping values.
Provides methods like isPresent(), orElse(), ifPresent().
Improves null-safety and reduces NullPointerExceptions.
Quick Summary: Optional is a container that may or may not contain a value - avoids null and NullPointerException. Create: Optional.of(value), Optional.ofNullable(valueOrNull), Optional.empty(). Consume: orElse(default), orElseGet(supplier), orElseThrow(), ifPresent(consumer), map(), flatMap(), filter(). Return Optional from methods that might not have a value. Don't use Optional as fields or method parameters.
Q26:

What is method reference in Java 8?

Entry

Answer

Method references provide shorthand for calling methods directly.
Examples: Class::staticMethod, object::instanceMethod, Class::new.
Reduce lambda verbosity.
Quick Summary: Method references are shorthand for lambdas that call an existing method. Types: ClassName::staticMethod (Static), object::instanceMethod (Bound instance), ClassName::instanceMethod (Unbound instance), ClassName::new (Constructor). Example: list.forEach(System.out::println) instead of list.forEach(s -> System.out.println(s)). More readable when the lambda just calls one method.
Q27:

Difference between map and flatMap in Streams.

Entry

Answer

map transforms each element individually.
flatMap flattens nested structures like lists inside streams.
Useful for handling nested collections.
Quick Summary: map() transforms each element with a function that returns a single value - Stream becomes Stream. flatMap() transforms each element with a function that returns a Stream, then flattens all those streams into one - useful for one-to-many transformations. Example: stream of sentences, flatMap to words: sentences.stream().flatMap(s -> Arrays.stream(s.split(" "))).
Q28:

Explain Collectors in Streams API.

Entry

Answer

Collectors accumulate stream elements into collections or other results.
Examples: toList(), toSet(), groupingBy(), joining().
Useful for aggregation and transformation.
Quick Summary: Collectors are terminal stream operations that accumulate results. Common: Collectors.toList(), toSet(), toMap(), groupingBy() (group into Map>), partitioningBy() (split into two groups by predicate), joining() (concatenate strings), counting(), summingInt(), averagingInt(). Combine with downstream collectors: groupingBy(key, counting()) counts per group.
Q29:

What are default and static methods in interfaces?

Entry

Answer

Default methods provide implementation inside interfaces.
Static methods belong to the interface and cannot be overridden.
Enhance flexibility and backward compatibility.
Quick Summary: Default methods in interfaces provide a default implementation - existing implementing classes don't need to add it. Enables interface evolution without breaking backward compatibility. Static methods in interfaces are utility methods tied to the interface (like Collections methods for Collection). Used heavily in Java 8 to add Stream/Lambda support to existing collection interfaces without breaking code.
Q30:

Explain the difference between sequential and parallel streams.

Entry

Answer

Sequential streams process elements one-by-one.
Parallel streams divide tasks into multiple threads.
Parallelism improves performance for large datasets when operations are thread-safe.
Quick Summary: Sequential streams process elements one at a time in the current thread. Parallel streams split the work across multiple threads using the ForkJoinPool. Parallel can be faster for large datasets with CPU-intensive operations but adds overhead (splitting, merging, thread management). Parallel is harmful for: small collections, I/O operations, stateful operations, or when order matters with side effects.
Q31:

How do Java 8 enhancements improve collection processing?

Entry

Answer

Lambdas reduce boilerplate.
Streams enable functional, chainable operations.
Collectors simplify grouping and aggregation.
Quick Summary: Java 8 collection enhancements: Iterable.forEach(consumer) - external loop. Collection.removeIf(predicate) - remove matching elements. List.sort(comparator). Map.forEach(), getOrDefault(), putIfAbsent(), computeIfAbsent(), merge(). Stream API for functional pipeline processing. These reduce boilerplate and enable more expressive collection processing without verbose loops.
Q32:

How do you handle exceptions in lambda expressions?

Entry

Answer

Checked exceptions must be handled inside lambda.
Custom functional interfaces can declare throws clauses.
Ensures clean functional-style error handling.
Quick Summary: Lambda bodies can only throw unchecked exceptions. To handle checked exceptions in lambdas: wrap in a try-catch inside the lambda, or create a helper functional interface that declares the checked exception, or use a utility method that wraps checked exceptions as unchecked. Alternatively, wrap the checked exception in a RuntimeException: e -> { try { ... } catch (IOException e) { throw new UncheckedIOException(e); } }
Q33:

Difference between Predicate, Function, Consumer, and Supplier.

Entry

Answer

Predicate tests conditions and returns boolean.
Function transforms input to output.
Consumer performs action without returning.
Supplier provides a value without input.
Quick Summary: Predicate: test(T t) returns boolean - used for filtering. Function: apply(T t) returns R - transformation. Consumer: accept(T t) returns void - side effects. Supplier: get() returns T - produces values. BiFunction, BiConsumer, BiPredicate handle two arguments. UnaryOperator is Function. BinaryOperator is BiFunction. These cover most functional programming needs.
Q34:

How do streams differ from traditional iteration?

Entry

Answer

Streams provide declarative processing.
Support lazy evaluation and parallelism.
Improve readability and performance for large datasets.
Quick Summary: Streams use internal iteration - you say what to do, the API handles how (can optimize, parallelize). Traditional iteration (for loop) uses external iteration - you control the loop. Streams are lazy (intermediate ops deferred), composable (chained pipelines), can be parallelized with one method call, and more declarative. Streams can only be consumed once - reuse the source to create a new stream.
Q35:

How do you group elements using Collectors?

Entry

Answer

groupingBy groups data by a key.
Supports downstream collectors like counting, summing, mapping.
Useful for analytics and reports.
Quick Summary: Collectors.groupingBy(classifier) groups stream elements into a Map>. Downstream collectors change the value: groupingBy(Person::getDept, counting()) gives Map. groupingBy(Person::getDept, toList()) is the default. Multi-level grouping: groupingBy(getDept, groupingBy(getCity)). toMap(keyMapper, valueMapper) for custom key-value extraction.
Q36:

Explain the use of peek() in streams.

Entry

Answer

peek is an intermediate operation for debugging.
Lets you inspect elements without modifying them.
Not intended for business logic.
Quick Summary: peek() is an intermediate operation that performs a side effect (like logging) for each element as it passes through, then passes the element unchanged to the next stage. Useful for debugging: stream.filter(x -> x > 0).peek(x -> log(x)).map(x -> x * 2). Don't use peek() to modify elements (it's for inspection only). Not guaranteed to run in all cases if terminal op short-circuits.
Q37:

Difference between Optional.map() and Optional.flatMap().

Entry

Answer

map transforms the wrapped value and wraps it again.
flatMap avoids nested Optionals by flattening results.
Useful with functions returning Optional.
Quick Summary: Optional.map() applies a function to the contained value if present, wrapping the result in Optional. If empty, returns empty. Optional.flatMap() applies a function that itself returns Optional and doesn't double-wrap - used to chain Optional-returning methods. map is for non-Optional-returning functions, flatMap for Optional-returning functions (avoids Optional>).
Q38:

Difference between immutable and unmodifiable collections.

Entry

Answer

Immutable collections cannot change after creation.
Unmodifiable collections prevent modification through wrapper but underlying data may still change.
Both enhance safety.
Quick Summary: Immutable collections (List.of(), Set.of(), Map.of() - Java 9+) can never be modified - add/remove/set throw UnsupportedOperationException and also disallow null elements. Unmodifiable collections (Collections.unmodifiableList()) are wrappers that reject mutations but the underlying collection can still be changed (through the original reference). Immutable is safer and allows more optimizations.
Q39:

How do you handle nulls in streams?

Entry

Answer

Use filter(Objects::nonNull) to remove nulls.
Wrap values with Optional to avoid null checks.
Prevents NullPointerExceptions.
Quick Summary: Handle nulls in streams: filter() with Objects::nonNull to remove nulls before processing. Optional.ofNullable() to wrap potentially null values. map() handles nulls poorly - returns a stream with null elements that blow up on later operations. For map values: use getOrDefault() or computeIfAbsent(). Consider using Optional upstream to avoid nulls entering the stream at all.
Q40:

What are the new Stream-related features in Java 9+?

Entry

Answer

Java 9+ adds ifPresentOrElse for Optional.
Collectors.teeing for combining results.
Factory methods like List.of(), Set.of(), Map.of().
Enhanced Stream.iterate() for bounded sequences.
Quick Summary: Java 9+ stream features: takeWhile(predicate) takes elements while condition is true then stops. dropWhile(predicate) skips elements while condition is true then takes the rest. Stream.iterate(seed, hasNext, next) finite iterate with termination condition. Stream.ofNullable(value) returns empty stream for null. These fill gaps that required workarounds in Java 8.
Q41:

Explain the four pillars of OOP in Java.

Junior

Answer

Encapsulation: Hides internal state and exposes only required methods.
Inheritance: Allows classes to reuse fields and methods.
Polymorphism: Treat objects as instances of parent type.
Abstraction: Hides implementation using abstract classes or interfaces.
Quick Summary: Four OOP pillars in Java: Encapsulation - wrap data and methods in a class, use private fields with public getters/setters. Inheritance - subclass extends superclass to reuse and add behavior (extends keyword). Polymorphism - object behaves differently based on actual type (method overriding). Abstraction - hide complex implementation behind simple interfaces (abstract classes, interfaces).
Q42:

Difference between abstract classes and interfaces.

Junior

Answer

Abstract classes can have fields, constructors, and concrete methods.
Interfaces declare abstract methods (plus default/static methods).
Java allows single inheritance for classes but multiple inheritance through interfaces.
Quick Summary: Abstract class: can have state (instance fields), constructors, concrete methods. Used for "is-a" relationships with shared implementation. A class can extend only one. Interface: no state (only constants), no constructors, all methods abstract by default (Java 8+ adds default/static). A class can implement many interfaces. Use abstract class for template base, interface for multiple capabilities/contracts.
Q43:

What is method overriding vs method overloading?

Junior

Answer

Overloading: Same method name, different parameters; compile-time polymorphism.
Overriding: Subclass redefines parent method; runtime polymorphism.
Overriding requires inheritance.
Quick Summary: Overriding: subclass replaces a parent method with the same name, return type, and parameters. Resolved at runtime - actual object type determines which method runs. Enables polymorphism. Overloading: same class has multiple methods with the same name but different parameters. Resolved at compile time based on argument types. Both are called polymorphism but at different times.
Q44:

How does the super keyword work?

Junior

Answer

super refers to parent class.
Used to call parent constructors or parent methods.
Helps resolve naming conflicts between superclass and subclass.
Quick Summary: super refers to the parent class. super.method() calls the parent's version of an overridden method. super.field accesses a parent field hidden by a subclass field. super() in a constructor calls the parent constructor - must be the first statement. If you don't call super() explicitly, Java automatically inserts a call to the parent's no-arg constructor.
Q45:

Explain constructor chaining in Java.

Junior

Answer

Constructor chaining calls one constructor from another using this().
super() calls parent constructor.
Ensures proper initialization and code reuse.
Quick Summary: Constructor chaining calls one constructor from another in the same class using this(), or calls the parent constructor using super(). this() call must be the first line. Useful for avoiding code duplication when multiple constructors share setup logic. Chain to the most specific constructor: the others call it with default values.
Q46:

What are static blocks and static methods?

Junior

Answer

Static block executes once when class loads.
Static methods belong to class and can be accessed without object creation.
Quick Summary: Static blocks run once when the class is loaded by JVM, before any instance creation. Used for complex static field initialization. Static methods belong to the class (not instance), can be called without an object, but can only access static members. Instance initializer blocks run before each constructor. Static initialization order: parent class first, then child.
Q47:

Difference between final, finally, and finalize.

Junior

Answer

final: Makes variables constant, classes non-inheritable, methods non-overridable.
finally: Executes after try/catch always.
finalize: Called before garbage collection (deprecated).
Quick Summary: final keyword: makes variable constant, method un-overridable, class un-extendable. finally block: always executes after try-catch, used to release resources (even if exception is thrown - except System.exit()). finalize() method: called by GC before reclaiming object memory - deprecated, unpredictable timing, don't use for cleanup. Use try-with-resources instead of finalize for resource cleanup.
Q48:

Explain Java exception hierarchy.

Junior

Answer

Throwable ? Error and Exception.
Error: Serious issues (not handled usually).
Exception: Can be handled.
Checked exceptions must be declared; unchecked are runtime exceptions.
Quick Summary: Exception hierarchy: Throwable at top. Two branches: Error (serious system problems - OutOfMemoryError, StackOverflowError - don't try to catch these) and Exception. Exception branches into: checked exceptions (must handle - IOException, SQLException) and unchecked/RuntimeException (NullPointerException, IllegalArgumentException, ArrayIndexOutOfBoundsException). RuntimeExceptions typically indicate programming bugs.
Q49:

How is multiple inheritance handled in Java?

Junior

Answer

Java does not support multiple inheritance of classes.
Achieved using interfaces.
Prevents diamond problem.
Quick Summary: Java doesn't support multiple class inheritance (a class can extend only one class) to avoid the diamond problem (ambiguous method resolution). Multiple interface inheritance is allowed - a class can implement many interfaces. Java 8 adds default methods to interfaces, handled with explicit override if two interfaces have conflicting defaults. This design simplifies inheritance while keeping flexibility.
Q50:

Explain object cloning in Java.

Junior

Answer

Cloning creates object copies.
Uses Cloneable interface.
Shallow copy copies references; deep copy duplicates full object graph.
Quick Summary: Object cloning creates a copy of an object. Shallow clone (Object.clone()): copies primitive fields by value and reference fields by reference - both original and clone point to the same nested objects. Deep clone: recursively copies all nested objects too. Implement Cloneable interface and override clone(). Alternatively, use copy constructors or serialization for deep copying.
Q51:

What is the difference between == and equals()?

Junior

Answer

== compares references.
equals() compares content.
equals() should be overridden for custom comparison.
Quick Summary: For objects: == checks if two references point to the same memory location (same object instance). equals() checks logical equality based on the implementation. By default, equals() uses == (reference equality). Override equals() to define meaningful equality (e.g., two Users are equal if they have the same userId). Always override hashCode() when you override equals().
Q52:

Explain hashCode() and equals() contract.

Junior

Answer

If two objects are equal via equals(), their hashCode() must match.
Required for HashMap, HashSet, and other collections.
Quick Summary: The contract: objects that are equal (equals() returns true) must have the same hashCode. Objects with the same hashCode may or may not be equal (hash collision). If you break this contract, HashMap and HashSet won't work correctly - equal objects would be stored in different buckets and never found. Always override both together. Use Objects.hash() for a clean implementation.
Q53:

How does the instanceof keyword work?

Junior

Answer

Checks whether an object belongs to a specific class or subclass.
Useful for safe type casting.
Quick Summary: instanceof checks if an object is an instance of a class or implements an interface at runtime. Returns true if the object is the specified type or a subtype. Usage: if (obj instanceof String s) (Java 16 pattern matching - casts and binds in one step). Use before downcasting to avoid ClassCastException. instanceof on null always returns false.
Q54:

Explain Java packages and access control.

Junior

Answer

Packages group related classes.
Access modifiers: public, private, protected, default.
Improves modularity and avoids naming conflicts.
Quick Summary: Packages group related classes and provide namespace separation. Access control per package: public (everywhere), protected (package + subclasses), default/package-private (same package only), private (class only). Classes in the same package can access each other's package-private members without importing. Use packages to organize code and control what's part of your public API.
Q55:

Difference between deep copy and shallow copy.

Junior

Answer

Shallow copy copies references; objects shared.
Deep copy duplicates all objects; independent copies.
Quick Summary: Shallow copy: creates a new object but copies reference fields by reference - the copy and original share the same nested objects. Modifying a nested object through either copy affects both. Deep copy: recursively copies all objects - completely independent copy. Shallow copy is fast but risky for mutable nested objects. Use serialization or copy constructors for deep copies.
Q56:

Explain Java memory model.

Junior

Answer

Memory divided into Heap (objects) and Stack (references & primitives).
Method area holds class data.
GC manages heap memory.
Quick Summary: Java Memory Model (JMM) defines how threads interact via shared memory. Key guarantees: volatile fields are always read from main memory (not thread-local cache). synchronized ensures visibility and atomicity - changes made inside synchronized block are visible to all threads after they acquire the same lock. JMM prevents data races when you use proper synchronization.
Q57:

How does garbage collection work in Java?

Junior

Answer

GC removes unreachable objects.
Algorithms include Mark-and-Sweep and Generational GC.
Prevents memory leaks automatically.
Quick Summary: Java GC works in generations. Eden (new objects), Survivor spaces (survived one GC), and Old Gen (long-lived objects). Minor GC: collects Eden and Survivor spaces - fast. Major/Full GC: collects Old Gen - slower, causes pause. GC algorithms: Serial (single-threaded), Parallel (throughput), G1 (balanced), ZGC/Shenandoah (low latency - sub-millisecond pauses). JVM automatically manages when GC runs.
Q58:

How do Java Strings differ from StringBuilder and StringBuffer?

Junior

Answer

String is immutable.
StringBuilder is mutable and faster but not thread-safe.
StringBuffer is thread-safe (synchronized).
Quick Summary: String is immutable - every "modification" creates a new String object. StringBuilder is mutable and fast but not thread-safe - use in single-threaded string building. StringBuffer is mutable and thread-safe (synchronized) but slower. For string concatenation in loops, always use StringBuilder to avoid creating many intermediate String objects. Java 9+ optimizes simple concatenations automatically.
Q59:

Explain Java enums.

Junior

Answer

Enums represent fixed constants.
Can have fields, constructors, and methods.
Improve type safety and readability.
Quick Summary: Enums define a fixed set of named constants. Better than integer constants: type-safe (compiler catches wrong values), can have methods and fields, work with switch statements, implement interfaces. Each enum value is a singleton instance. Enum has built-in methods: name(), ordinal(), values(), valueOf(). EnumSet and EnumMap are highly efficient collections for enums.
Q60:

What are Java annotations?

Junior

Answer

Annotations provide metadata for code.
Affect compilation or runtime behavior.
Examples: @Override, @Deprecated, @SuppressWarnings.
Quick Summary: Annotations are metadata attached to code elements (classes, methods, fields). Built-in: @Override (verify you're overriding), @Deprecated (mark as obsolete), @SuppressWarnings. Create custom annotations with @interface. Frameworks use annotations heavily for configuration (Spring @Component, @Autowired; JPA @Entity, @Column). Annotations are processed at compile time (retention COMPILE) or runtime (retention RUNTIME via reflection).
Q61:

What are the main interfaces of the Java Collections Framework?

Junior

Answer

List: Ordered collection allowing duplicates.
Set: No duplicates, unordered or sorted.
Map: Key-value pairs with unique keys.
Queue/Deque: FIFO or double-ended structures.
Iterable: Base interface enabling iteration.
Quick Summary: Main collection interfaces: Collection (root), List (ordered, duplicates allowed - ArrayList, LinkedList), Set (no duplicates - HashSet, TreeSet, LinkedHashSet), Map (key-value - HashMap, TreeMap, LinkedHashMap), Queue (FIFO - LinkedList, PriorityQueue), Deque (double-ended queue). Program to interfaces (List not ArrayList) for flexibility to swap implementations.
Q62:

What is the difference between ArrayList and LinkedList?

Junior

Answer

ArrayList: Backed by array; fast random access; slower insert/delete in middle.
LinkedList: Doubly linked nodes; fast insert/delete; slow random access.
Quick Summary: ArrayList: backed by an array, O(1) random access by index, O(n) insertion/deletion in the middle (elements shift), fast iteration. LinkedList: doubly-linked list, O(1) insertion/deletion at head/tail, O(n) random access, more memory (stores pointers). Choose ArrayList for most cases. Use LinkedList only when you frequently add/remove from both ends.
Q63:

What is the difference between HashMap, TreeMap, and LinkedHashMap?

Junior

Answer

HashMap: Unordered, fast via hashing.
TreeMap: Sorted keys, uses Red-Black tree.
LinkedHashMap: Maintains insertion order.
Quick Summary: HashMap: O(1) average get/put, no ordering, allows one null key. TreeMap: sorted by key (natural order or Comparator), O(log n) operations, no null keys. LinkedHashMap: maintains insertion order (or access order for LRU cache), O(1) operations. Use HashMap for performance, TreeMap when you need sorted keys, LinkedHashMap when insertion order matters.
Q64:

Explain the difference between List, Set, and Map.

Junior

Answer

List: Ordered, allows duplicates.
Set: No duplicates.
Map: Key-value pairs with unique keys.
Quick Summary: List: ordered sequence, allows duplicates, access by index. Set: unordered (HashSet) or sorted (TreeSet), no duplicates - add() returns false if duplicate. Map: key-value pairs, keys are unique (Set semantics for keys), values can duplicate. Use List for ordered data with duplicates, Set for uniqueness enforcement, Map for key-based lookups.
Q65:

What are Java generics and why use them?

Junior

Answer

Generics provide compile-time type safety.
Enable reusable classes and methods.
Reduce casting and runtime errors.
Quick Summary: Generics add compile-time type safety to collections and algorithms. Without generics: List stores Object, need casting, ClassCastException possible at runtime. With generics: List only holds Strings, no casting needed, wrong types caught at compile time. Write generic methods and classes with type parameters: , , . Type erasure means generics exist only at compile time.
Q66:

How do wildcards in generics work?

Junior

Answer

? extends T: Accepts T or subclasses.
? super T: Accepts T or superclasses.
Used for flexible yet safe type handling.
Quick Summary: Wildcards represent unknown types in generics. ? (unbounded): accepts any type - useful for reading. ? extends T (upper bounded): accepts T or subtypes - can read as T, can't write. ? super T (lower bounded): accepts T or supertypes - can write T, reading gives Object. Remember PECS: Producer Extends (read-only), Consumer Super (write-only).
Q67:

What is the difference between Comparable and Comparator?

Junior

Answer

Comparable: Natural ordering defined in class.
Comparator: External custom sorting logic.
Both used during sorting.
Quick Summary: Comparable: implemented by the class itself (implements Comparable), defines "natural ordering" via compareTo(). Used by sort() and sorted collections automatically. Comparator: external comparison logic - doesn't modify the class. Pass to sort(), TreeMap, sorted collections. Comparator is more flexible - create multiple comparison strategies. Java 8: Comparator.comparing(Person::getAge).thenComparing(Person::getName).
Q68:

What is the difference between fail-fast and fail-safe iterators?

Junior

Answer

Fail-fast: Throws ConcurrentModificationException.
Fail-safe: Works on copy; allows modification.
Quick Summary: Fail-fast iterators (ArrayList, HashMap) throw ConcurrentModificationException if the collection is modified during iteration (checks modCount). This is to prevent unpredictable behavior, not thread safety. Fail-safe iterators (CopyOnWriteArrayList, ConcurrentHashMap) work on a snapshot of the collection - modifications during iteration are safe but not reflected in the current iteration.
Q69:

Explain Java multithreading.

Junior

Answer

Thread is independent execution path.
Runnable defines thread task.
Lifecycle: New ? Runnable ? Running ? Waiting/Blocked ? Terminated.
Quick Summary: Multithreading allows concurrent execution of multiple threads within one process. Threads share the same memory (heap), unlike processes. Benefits: better CPU utilization, responsive UIs, parallel processing. Challenges: race conditions, deadlocks, visibility issues. Java provides built-in threading support: Thread class, Runnable interface, synchronized keyword, and java.util.concurrent package.
Q70:

How do you create and start a thread?

Junior

Answer

Extend Thread or implement Runnable.
Call start() to run thread asynchronously.
Thread pools manage multiple threads efficiently.
Quick Summary: Two ways to create threads: extend Thread class and override run(), or implement Runnable interface and pass to Thread constructor. Prefer Runnable - it doesn't waste your single inheritance. Java 8+: use lambdas: new Thread(() -> doWork()).start(). Better yet, use ExecutorService to manage thread pools instead of creating threads manually.
Q71:

What are synchronized methods and blocks?

Junior

Answer

Ensure exclusive access to shared resources.
Prevent race conditions.
Synchronized block gives finer locking control.
Quick Summary: synchronized prevents concurrent access to a code block or method. Synchronized method: only one thread can execute it on the same object at a time. Synchronized block: more fine-grained, lock on any object. Guarantees mutual exclusion and memory visibility (changes in synchronized block visible to all threads after they acquire same lock). Downside: performance overhead if contended.
Q72:

Explain inter-thread communication.

Junior

Answer

Uses wait(), notify(), notifyAll().
Helps coordinate producer-consumer tasks.
Must be inside synchronized blocks.
Quick Summary: Inter-thread communication uses wait(), notify(), notifyAll() on a shared object. wait() releases the lock and puts the thread to sleep until notified. notify() wakes one waiting thread. notifyAll() wakes all. Must be called within a synchronized block on the same object. Used for producer-consumer pattern. Modern code uses BlockingQueue instead - much simpler and less error-prone.
Q73:

What are deadlocks and how do you prevent them?

Junior

Answer

Deadlock: Threads wait forever for each other's locks.
Prevent by avoiding nested locks, ordering locks consistently, or using timeouts.
Quick Summary: Deadlock: thread A holds lock X and waits for lock Y. Thread B holds lock Y and waits for lock X. Both wait forever. Prevention: always acquire locks in the same order across all threads. Alternatively: use tryLock() with timeout (ReentrantLock), use lock-free data structures, minimize lock scope, or avoid nested locks entirely. Use thread dumps to diagnose deadlocks in production.
Q74:

What is the difference between volatile, synchronized, and atomic variables?

Junior

Answer

volatile: Ensures visibility of changes.
synchronized: Ensures mutual exclusion.
Atomic variables: Lock-free thread-safe operations.
Quick Summary: volatile: ensures a variable is always read from main memory (not CPU cache) - fixes visibility, not atomicity. Reads/writes are not atomic for long/double. synchronized: mutual exclusion + visibility - all operations inside are atomic. Atomic (AtomicInteger etc.): lock-free atomic operations using CAS (compare-and-swap) - faster than synchronized for simple counters and flags.
Q75:

Explain thread priorities and scheduling.

Junior

Answer

Threads have priorities (1–10).
Higher priority gets more CPU time but no guaranteed order.
Actual scheduling depends on OS and JVM.
Quick Summary: Thread priorities (MIN=1, NORM=5, MAX=10) hint to the OS scheduler which threads to prefer. Not guaranteed - OS is free to ignore hints. Starvation risk: high-priority threads always running can prevent low-priority threads from running. In practice, thread priorities are unreliable across platforms. Better to use proper synchronization and design rather than relying on priorities.
Q76:

Explain thread pools in Java.

Junior

Answer

Thread pools reuse worker threads.
Reduce overhead of thread creation.
Executors provide fixed, cached, and scheduled pools.
Quick Summary: Thread pool reuses a fixed number of threads to execute many tasks. Creating a new thread for every task is expensive. ExecutorService manages a pool: submit tasks, threads are reused. Common pools: Executors.newFixedThreadPool(n), newCachedThreadPool(), newSingleThreadExecutor(). Use ThreadPoolExecutor for fine-grained control. Always shut down the executor when done.
Q77:

What is the difference between Callable and Runnable?

Junior

Answer

Runnable: No return value; no checked exceptions.
Callable: Returns value and may throw exceptions.
Used with ExecutorService to get Future results.
Quick Summary: Runnable: run() method, no return value, can't throw checked exceptions. Callable: call() method, returns a value (Future), can throw checked exceptions. Use Callable when you need the result of an async computation. Submit to ExecutorService: Future future = executor.submit(callable); result = future.get() (blocks until done).
Q78:

Explain Java concurrent collections.

Junior

Answer

Thread-safe optimized collections.
Examples: ConcurrentHashMap, CopyOnWriteArrayList.
Avoids manual synchronization.
Quick Summary: java.util.concurrent provides thread-safe collections: ConcurrentHashMap (segmented locking, much better than synchronized HashMap), CopyOnWriteArrayList (thread-safe for read-heavy scenarios, writes copy the entire array), BlockingQueue (LinkedBlockingQueue, ArrayBlockingQueue - blocks producer/consumer when full/empty), ConcurrentLinkedQueue (lock-free). Choose based on read/write ratio and blocking needs.
Q79:

Explain producer-consumer problem in Java.

Junior

Answer

Producer adds data; consumer removes it.
Requires thread coordination and shared buffers.
Uses wait(), notify(), or BlockingQueue.
Quick Summary: Producer-consumer: producer puts items in a shared buffer, consumer takes them. Without coordination: producer overwhelms buffer (full) or consumer reads empty buffer. Solution: BlockingQueue - put() blocks if full, take() blocks if empty, no explicit wait/notify needed. ArrayBlockingQueue (bounded, prevents OOM) or LinkedBlockingQueue (unbounded). Much simpler than manual wait/notify.
Q80:

How do you handle thread safety in Java?

Junior

Answer

Use synchronization, locks, atomic variables, and concurrent collections.
Avoid shared mutable state.
Design carefully for safe concurrent execution.
Quick Summary: Thread safety means code works correctly when accessed by multiple threads concurrently. Strategies: immutability (immutable objects need no synchronization), synchronized methods/blocks, java.util.concurrent atomic classes, concurrent collections, ThreadLocal (each thread has its own copy). The best code is stateless or uses immutable shared state - requires no synchronization at all.
Q81:

Explain the Java Memory Model (JMM).

Mid

Answer

Java Memory Model defines visibility, ordering, and atomicity rules.
Heap stores objects; Stack stores references and local variables.
Method area stores class metadata.
PC register tracks execution.
Garbage collector manages heap memory automatically.
Quick Summary: JMM defines rules for visibility and ordering of memory operations across threads. Without JMM rules, CPUs and compilers can reorder operations for optimization. Key rules: volatile read/write creates happens-before. Monitor unlock happens-before subsequent lock on same monitor. Thread start happens-before first action in started thread. These rules ensure correct behavior without locking everything.
Q82:

What is the role of JVM, JIT, and bytecode?

Mid

Answer

JVM executes Java bytecode across platforms.
Bytecode is the intermediate compiled code.
JIT compiler converts bytecode to native machine code at runtime for faster execution.
Quick Summary: JVM (Java Virtual Machine) executes bytecode and provides memory management, GC, and security. JIT (Just-In-Time) compiler optimizes hot methods at runtime - compiles frequently executed bytecode to native machine code. Bytecode is the compiled output of Java source - platform-independent intermediary. JIT makes Java nearly as fast as C++ for long-running applications by optimizing hot paths.
Q83:

Explain garbage collection algorithms in Java.

Mid

Answer

Mark-and-Sweep marks live objects and removes unused ones.
Generational GC optimizes by separating objects into young and old generations.
Stop-the-world pauses occur during GC phases.
Modern collectors like G1 and ZGC reduce latency.
Quick Summary: Java GC algorithms: Serial (single-threaded, for small heaps), Parallel/Throughput (multi-threaded GC, good for batch processing), CMS (Concurrent Mark Sweep - deprecated, low pause), G1 (default since Java 9 - region-based, balances throughput and latency), ZGC (Java 11+ - sub-millisecond pauses for huge heaps), Shenandoah (similar to ZGC). Choose based on your latency vs throughput requirements.
Q84:

What are soft, weak, and phantom references?

Mid

Answer

SoftReference cleared when memory is low; used for caching.
WeakReference cleared during GC if no strong references exist.
PhantomReference used for cleanup before object collection.
Quick Summary: Reference types control GC behavior. Strong reference (normal): GC never collects. Soft reference (SoftReference): GC collects only when memory is low - good for caches. Weak reference (WeakReference): GC collects at next GC cycle - useful for canonicalization maps. Phantom reference (PhantomReference): enqueued after object is collected - for cleanup after GC. WeakHashMap uses weak keys.
Q85:

Explain Java ClassLoaders.

Mid

Answer

ClassLoaders load classes dynamically at runtime.
Types: Bootstrap, Extension, System, and Custom loaders.
Enable modularity, dynamic behavior, and class reloading.
Quick Summary: ClassLoaders load class files into the JVM. Hierarchy: Bootstrap (loads core Java classes from rt.jar), Extension (loads ext/ directory classes), Application/System (loads your app's classpath). Parent delegation model: child loader asks parent first before loading itself - prevents duplicate loading and security exploits. Custom ClassLoaders enable hot reloading and plugins (OSGi, application servers).
Q86:

How do you implement multithreading optimizations?

Mid

Answer

Use immutable objects for thread safety.
Prefer concurrent collections and atomic variables.
Minimize synchronized blocks.
Use thread pools for efficient thread reuse.
Quick Summary: Multithreading optimizations: use thread pools (avoid thread creation overhead), prefer lock-free structures (AtomicInteger, ConcurrentHashMap), minimize lock scope (hold locks for shortest time possible), use volatile for simple visibility (cheaper than synchronized), avoid false sharing (pad objects to cache line size), prefer immutable objects (zero sync cost), and profile before optimizing.
Q87:

Explain the difference between process and thread in Java.

Mid

Answer

Process: Independent execution with separate memory.
Thread: Lightweight execution sharing memory within a process.
Threads improve concurrency; processes ensure isolation.
Quick Summary: Process: independent program with its own memory space, expensive to create and switch, communication via IPC. Thread: lightweight execution unit within a process, shares process memory (heap), cheap to create, communication via shared memory (but needs synchronization). Java threads share heap but each has its own stack, program counter, and registers.
Q88:

What is the difference between checked and unchecked exceptions in multithreaded contexts?

Mid

Answer

Checked exceptions must be declared or handled.
Unchecked exceptions do not require declaration.
Threads must handle exceptions internally; unhandled runtime exceptions terminate threads.
Quick Summary: In multithreaded code: checked exceptions in Callable.call() are wrapped in ExecutionException when retrieved via Future.get(). In Runnable.run(), checked exceptions must be caught internally or wrapped in RuntimeException. CompletableFuture.exceptionally() and handle() catch async exceptions. Thread.UncaughtExceptionHandler catches exceptions that escape thread run() methods.
Q89:

Explain the Singleton design pattern in Java.

Mid

Answer

Ensures one instance of a class exists.
Implement using eager loading, lazy loading, double-checked locking, or enum.
Provides global access to the instance.
Quick Summary: Singleton ensures only one instance of a class exists. Implementation: private constructor, static getInstance() method. Thread-safe options: eager initialization (static final field), synchronized getInstance() (slow), double-checked locking with volatile (fast, correct in Java 5+), or the enum singleton (simplest and thread-safe by JVM guarantee). Use dependency injection instead of Singleton where possible.
Q90:

Explain the Factory design pattern.

Mid

Answer

Factory pattern creates objects without exposing creation logic.
Promotes loose coupling and extensibility.
Used in dependency injection and plugin architectures.
Quick Summary: Factory pattern creates objects without exposing instantiation logic to the client. Factory Method: subclass decides which class to instantiate. Abstract Factory: family of related objects created together. Benefits: decouples creation from usage, easy to swap implementations, centralize creation logic. Spring's ApplicationContext is a factory - you ask for a bean, it creates/returns it.
Q91:

Explain the Observer design pattern.

Mid

Answer

Defines one-to-many relationship between objects.
Observers are notified automatically on state changes.
Useful for event-driven systems and GUIs.
Quick Summary: Observer pattern defines a one-to-many dependency. When one object (subject/observable) changes state, all registered observers are notified automatically. Java built-in: Observable class (deprecated), PropertyChangeListener. Modern approach: event buses (Guava EventBus), reactive streams (RxJava, Project Reactor). Used in GUI event handling, MVC pattern (model notifies views), messaging systems.
Q92:

Explain the Strategy design pattern.

Mid

Answer

Encapsulates algorithms into separate classes.
Allows changing behavior at runtime.
Improves flexibility and maintainability.
Quick Summary: Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. The context object holds a reference to a strategy interface and delegates work to it. Swap strategies at runtime. Example: sorting algorithms, payment processors, compression algorithms. In Java, lambdas are essentially Strategy objects for functional interfaces - replaces many traditional Strategy implementations.
Q93:

Explain the Decorator design pattern.

Mid

Answer

Adds behavior to objects dynamically without modifying class.
Promotes composition over inheritance.
Used in I/O streams and UI components.
Quick Summary: Decorator pattern adds behavior to an object dynamically without modifying its class or using inheritance. Wrap the original object in a decorator that adds functionality and delegates to the original. Stackable - wrap multiple decorators. Java I/O streams are classic decorators: BufferedInputStream wraps FileInputStream, adding buffering. Enables open/closed principle - extend behavior without modifying existing code.
Q94:

Explain the Adapter design pattern.

Mid

Answer

Converts interface of one class into another expected by client.
Enables integration of incompatible systems.
Useful for legacy code and third-party APIs.
Quick Summary: Adapter pattern makes incompatible interfaces work together. Creates a wrapper (adapter) that translates one interface into another. Object adapter: holds a reference to the adaptee, translates calls. Class adapter: extends the adaptee (rare in Java due to single inheritance). Example: java.io.InputStreamReader adapts InputStream (byte stream) to Reader (character stream) interface.
Q95:

Explain the Proxy design pattern.

Mid

Answer

Provides a surrogate object to control access to another object.
Used for lazy loading, security, caching, and remote proxies.
Quick Summary: Proxy pattern provides a surrogate that controls access to another object. Types: Virtual proxy (lazy initialization - create expensive object only when needed), Protection proxy (access control), Remote proxy (represents object in another JVM/network - Java RMI), Logging/caching proxy. Spring AOP uses dynamic proxies to add cross-cutting concerns (transactions, security, logging) without modifying your code.
Q96:

Explain Java volatile and its role in concurrency.

Mid

Answer

volatile ensures visibility of variable changes.
Prevents instruction reordering for that variable.
Does not guarantee atomicity for compound operations.
Quick Summary: volatile ensures a variable is read from and written to main memory, not a CPU-specific cache. Solves the visibility problem - one thread's write is immediately visible to all other threads. Does NOT guarantee atomicity - volatile int count++ is still a read-modify-write race condition (use AtomicInteger instead). Use volatile for simple flags (boolean running = true/false) and singleton double-checked locking.
Q97:

Explain Java Atomic classes.

Mid

Answer

Provide lock-free thread-safe operations.
Examples: AtomicInteger, AtomicBoolean, AtomicReference.
Faster than synchronized blocks for single-variable operations.
Quick Summary: Atomic classes (AtomicInteger, AtomicLong, AtomicBoolean, AtomicReference) provide lock-free thread-safe operations using CPU-level CAS (Compare-And-Swap). compareAndSet(expected, newValue) atomically updates only if current value matches expected - retries on failure. Faster than synchronized for simple counter/flag scenarios because no thread blocking. Used for high-performance counters and accumulators.
Q98:

What are Java locks and ReentrantLocks?

Mid

Answer

Locks provide advanced synchronization features.
ReentrantLock allows same thread to re-acquire lock.
Supports fairness, tryLock, timed locking, and conditions.
Quick Summary: ReentrantLock provides more control than synchronized: tryLock() (non-blocking attempt with optional timeout), lockInterruptibly() (can be interrupted while waiting), fair mode (threads acquire in order of waiting), and separate Condition objects (like multiple wait/notify queues). More powerful than synchronized but more verbose. Prefer synchronized for simple cases, ReentrantLock for advanced scenarios.
Q99:

How does Java handle thread pools?

Mid

Answer

ExecutorService manages thread pools.
Reduces overhead of thread creation.
Supports scheduled and concurrent task execution.
Quick Summary: Java thread pools (ExecutorService) reuse threads for multiple tasks. ThreadPoolExecutor core params: corePoolSize (always kept alive), maximumPoolSize (max threads), keepAliveTime (idle thread timeout), and BlockingQueue (task queue). When queue is full and max threads reached, RejectedExecutionHandler kicks in. Use Executors factory for common configurations, ThreadPoolExecutor for custom.
Q100:

Explain Java memory optimization strategies.

Mid

Answer

Use primitive types when possible.
Avoid unnecessary object creation.
Apply lazy initialization and caching.
Choose efficient collections.
Minimize object retention to help GC.
Quick Summary: Java memory optimization: use primitives instead of wrappers where possible, avoid unnecessary object creation, reuse objects (object pools for expensive objects), use StringBuilder instead of String concatenation in loops, be aware of autoboxing in collections, use weak/soft references for caches, tune GC with appropriate heap sizes and GC algorithm for your workload.
Q101:

Explain Java concurrency utilities.

Senior

Answer

The java.util.concurrent package provides high-level concurrency support.
Includes ExecutorService, ThreadPoolExecutor, ScheduledExecutorService, BlockingQueue, Semaphore, CountDownLatch.
Reduces boilerplate synchronization and improves performance in multithreaded applications.
Quick Summary: java.util.concurrent provides: Executors/ExecutorService (thread pools), Future/CompletableFuture (async results), BlockingQueue (producer-consumer), ConcurrentHashMap/CopyOnWriteArrayList (thread-safe collections), AtomicInteger/AtomicReference (lock-free atomics), Semaphore/CountDownLatch/CyclicBarrier (coordination), and StampedLock/ReentrantReadWriteLock (read-write locking).
Q102:

What is ExecutorService and why is it used?

Senior

Answer

ExecutorService manages threads and executes tasks asynchronously.
Supports thread pools, scheduling, submit(), invokeAll(), shutdown().
Improves resource management and avoids manual thread creation.
Quick Summary: ExecutorService manages a thread pool and submits tasks. Benefits over manual thread creation: thread reuse (no creation overhead), task queuing, controlled parallelism (fixed pool prevents resource exhaustion), and built-in lifecycle management. Key methods: submit() (returns Future), execute() (fire-and-forget), shutdown() (wait for tasks to complete), shutdownNow() (interrupt running tasks).
Q103:

Difference between Callable and Runnable.

Senior

Answer

Runnable has no return value and cannot throw checked exceptions.
Callable returns values and can throw exceptions.
Callable works with Future for asynchronous results.
Quick Summary: Runnable.run() takes no args, returns void, can't throw checked exceptions. Callable.call() takes no args, returns a value (V), can throw checked exceptions. Use Runnable with execute(). Use Callable with submit() which returns Future - get() blocks until result is ready, throws ExecutionException wrapping any exception thrown in call(). CompletableFuture is the modern, composable alternative.
Q104:

Explain Future and CompletableFuture.

Senior

Answer

Future represents the result of an asynchronous computation.
CompletableFuture extends Future with non-blocking, chainable, and combinational operations.
Useful for reactive, asynchronous workflows.
Quick Summary: Future represents a pending async result. get() blocks until done (optionally with timeout). Limited: can't chain, no callbacks, no combining multiple futures. CompletableFuture (Java 8+) is much richer: thenApply() (transform result), thenCompose() (chain futures), thenCombine() (combine two futures), exceptionally() (handle errors), allOf() (wait for all), anyOf() (first to complete). Non-blocking with callbacks.
Q105:

Difference between synchronized and ReentrantLock.

Senior

Answer

synchronized is simple and blocks until a lock is released.
ReentrantLock provides tryLock(), timeouts, fairness, and multiple conditions.
ReentrantLock offers more control and flexibility.
Quick Summary: synchronized: built-in, simpler syntax, automatic lock release. ReentrantLock: explicit lock()/unlock() (must use try-finally), tryLock() with timeout (avoids deadlock), lockInterruptibly(), fair mode, multiple Condition objects. ReentrantReadWriteLock: multiple concurrent readers, exclusive writer - great for read-heavy shared data. Use synchronized for simple cases, ReentrantLock for complex concurrency requirements.
Q106:

Explain CountDownLatch, CyclicBarrier, and Semaphore.

Senior

Answer

CountDownLatch waits for a set of threads to finish.
CyclicBarrier allows threads to wait for each other repeatedly.
Semaphore controls access to limited resources using permits.
Quick Summary: CountDownLatch: one-time gate - await() blocks until count reaches zero. Used to wait for N tasks to complete. CyclicBarrier: reusable rendezvous - await() blocks until N threads all arrive, then all proceed together. Used for parallel computation phases. Semaphore: limits N concurrent accesses to a resource. acquire() blocks if permits exhausted, release() returns a permit. All are in java.util.concurrent.
Q107:

How does Java ensure thread safety?

Senior

Answer

Thread safety is achieved using synchronized blocks, locks, atomic variables, and concurrent collections.
Prefer immutability and minimize shared mutable state.
Use functional programming constructs where possible.
Quick Summary: Thread safety approaches: make classes stateless (no shared mutable state = automatically thread-safe), use immutable objects (share freely), use synchronized or locks for mutable shared state, use concurrent collections (ConcurrentHashMap), use atomic variables (AtomicInteger), or use ThreadLocal to give each thread its own copy. The safest code avoids shared mutable state entirely.
Q108:

Explain volatile keyword and atomicity.

Senior

Answer

volatile guarantees visibility of updates across threads.
Does not ensure atomic operations for increments or composite actions.
Use atomic classes or synchronization for atomicity.
Quick Summary: volatile ensures visibility: reads come from main memory, writes go directly to main memory (not CPU cache). Does NOT ensure atomicity. count++ on a volatile int is still a race condition (read, increment, write - three separate operations). For atomic operations use AtomicInteger.incrementAndGet(). volatile is correct for: simple boolean flags, double-checked locking with proper pattern.
Q109:

Explain parallel streams.

Senior

Answer

Parallel streams process data using multiple threads.
Increase performance for CPU-intensive tasks.
Operations must be thread-safe to avoid race conditions.
Quick Summary: list.parallelStream() processes the stream using the common ForkJoinPool (default: CPU core count - 1). The pipeline is split into chunks, processed in parallel, then merged. Good for: large datasets, CPU-intensive operations, stateless operations. Bad for: small collections (overhead > benefit), I/O operations (threads block), order-sensitive side effects. Profile before using parallel - it's not always faster.
Q110:

Explain Fork/Join framework.

Senior

Answer

Fork/Join supports parallel processing using divide-and-conquer approach.
Uses ForkJoinPool and RecursiveTask or RecursiveAction.
Ideal for large recursive computations.
Quick Summary: Fork/Join splits a task recursively into smaller subtasks (fork), processes them in parallel, then combines results (join). Uses work-stealing: idle threads steal tasks from busy threads' queues. Implement RecursiveTask (returns result) or RecursiveAction (no result). Use ForkJoinPool or parallelStream (which uses the common ForkJoinPool internally). Best for divide-and-conquer algorithms on large datasets.
Q111:

How do you avoid deadlocks?

Senior

Answer

Acquire locks in a consistent order.
Avoid nested locks where possible.
Use tryLock() or timed locks.
Prefer higher-level concurrency utilities.
Quick Summary: Avoid deadlocks: always acquire multiple locks in the same consistent order across all threads. Use tryLock() with timeout instead of lock() - if timeout expires, release what you have and retry. Minimize lock scope and duration. Use lock-free data structures (AtomicInteger, ConcurrentHashMap) when possible. Use a single lock instead of multiple locks when feasible. Detect with thread dumps (jstack).
Q112:

Explain ThreadLocal.

Senior

Answer

ThreadLocal stores per-thread variables.
Each thread gets its own isolated copy.
Useful for caching, user sessions, or context propagation.
Quick Summary: ThreadLocal gives each thread its own independent variable copy. Changes in one thread don't affect other threads. Common use: per-request context (user session, database connection, locale) in web frameworks. Spring's RequestContextHolder uses ThreadLocal. Important: always remove() when done (especially in thread pools - threads are reused and old values persist, causing bugs and memory leaks).
Q113:

Explain CompletableFuture chaining.

Senior

Answer

CompletableFuture allows async task chaining with thenApply, thenAccept, thenCombine, exceptionally.
Enables building non-blocking, reactive pipelines.
Quick Summary: CompletableFuture chaining: thenApply(fn) transforms result synchronously. thenApplyAsync(fn) transforms in another thread. thenCompose(fn) chains another CompletableFuture (flatMap). thenCombine(other, fn) combines two futures' results when both complete. thenAccept(consumer) consumes without returning. Build complex async pipelines: fetch data -> transform -> combine -> handle errors -> deliver result.
Q114:

Difference between parallel streams and CompletableFuture.

Senior

Answer

Parallel streams provide easy parallelism for collection processing.
CompletableFuture gives fine-grained control over async tasks.
Use based on concurrency requirements and task complexity.
Quick Summary: Parallel streams use the shared ForkJoinPool - all parallel streams compete for the same threads. CompletableFuture lets you specify your own executor (isolate from shared pool), compose complex async workflows with callbacks (non-blocking), and handle errors per step. Use parallel streams for simple CPU-intensive pipelines. Use CompletableFuture for complex async workflows, I/O operations, and when you need control over thread pools.
Q115:

How does Java handle thread priorities?

Senior

Answer

Threads have priorities from 1 to 10.
Higher-priority threads are scheduled preferentially but order is not guaranteed.
Actual scheduling depends on JVM and OS.
Quick Summary: Thread priorities (1-10, default 5) hint to the OS scheduler but aren't guaranteed. The JVM maps Java priorities to OS-level priorities which vary by platform. High-priority threads get more CPU time but low-priority threads can still run. Thread.MIN_PRIORITY=1, NORM_PRIORITY=5, MAX_PRIORITY=10. Don't rely on priorities for correctness - use proper synchronization instead.
Q116:

Explain reactive programming in Java.

Senior

Answer

Reactive programming uses asynchronous, non-blocking data streams.
Implemented via libraries like RxJava and Reactor.
Useful for microservices, streaming, and event-driven systems.
Quick Summary: Reactive programming in Java handles async event streams with backpressure. Libraries: Project Reactor (Spring WebFlux) and RxJava. Core types: Mono (0 or 1 element), Flux (0 to N elements). Operators: map, flatMap, filter, zip. Backpressure lets consumers signal producers to slow down. Benefits: non-blocking end-to-end, high throughput with few threads, composable async pipelines.
Q117:

Explain CompletableFuture vs Future.

Senior

Answer

Future is limited; get() is blocking and lacks chaining.
CompletableFuture supports non-blocking operations, chaining, combination, and exception handling.
More powerful for async workflows.
Quick Summary: Future: get() blocks the calling thread, no callbacks, can't compose multiple futures, limited error handling. CompletableFuture: non-blocking callbacks (thenApply, thenAccept), composable (thenCompose, thenCombine), built-in exception handling (exceptionally, handle), can be manually completed (complete(), completeExceptionally()). CompletableFuture is strictly superior for complex async workflows.
Q118:

How do you handle exceptions in parallel processing?

Senior

Answer

Handle exceptions inside threads individually.
Use CompletableFuture.exceptionally() or handle().
Avoid uncaught exceptions that silently terminate threads.
Quick Summary: In parallel streams, exceptions in one thread are wrapped in a RuntimeException and rethrown in the calling thread. Use a try-catch around the terminal operation. In CompletableFuture, use exceptionally(fn) to handle exceptions per step, or handle(fn) which gets both result and exception. In ExecutorService, exceptions from Callable are wrapped in ExecutionException from Future.get().
Q119:

Best practices for thread safety and performance.

Senior

Answer

Prefer immutability and stateless logic.
Minimize synchronized sections.
Use atomic types and concurrent collections.
Load-test multithreaded code thoroughly.
Quick Summary: Thread safety and performance best practices: prefer immutability (zero synchronization cost), use concurrent collections instead of synchronized wrappers, minimize lock scope (only lock around the actual shared state, not expensive operations), avoid nested locks (deadlock risk), use lock-free atomics for counters/flags, profile to find actual bottlenecks before optimizing, and use VirtualThreads (Java 21) for I/O-bound tasks.
Q120:

Modern Java features for performance optimization.

Senior

Answer

Use streams and parallel streams carefully.
Use Fork/Join for divide-and-conquer workloads.
Leverage CompletableFuture for async tasks.
Prefer immutable objects to reduce synchronization overhead.
Quick Summary: Modern Java performance features: Virtual Threads (Java 21) - millions of lightweight threads for I/O-bound workloads. Records (Java 16) - compact immutable value objects. Sealed classes for exhaustive pattern matching. JEP improvements to GC (ZGC, Shenandoah with sub-ms pauses). String templates (Java 21). Vector API for SIMD operations. Always profile with JMH before claiming an optimization helps.

Curated Sets for Java

No curated sets yet. Group questions into collections from the admin panel to feature them here.

Ready to level up? Start Practice