Java Int Questions
Java Int Questions
QUESTIONS
1. Java Basics
1. What are the main features of Java?
2. What is the difference between JDK, JRE, and JVM?
3. What is the difference between == and .equals()?
4. How does Java achieve platform independence?
5. What is the main method signature in Java?
5. Collections Framework
1. Difference between ArrayList and LinkedList.
2. How does HashMap work internally?
3. Difference between HashMap, TreeMap, and LinkedHashMap.
4. What are HashSet, TreeSet, and their use cases?
5. Fail-fast vs fail-safe iterators?
6. Exception Handling
1. Difference between Checked and Unchecked exceptions.
2. What is the purpose of finally block?
3. Can you catch multiple exceptions in a single catch block?
4. Custom exceptions: how and when to create one?
12. Miscellaneous
1. What is serialization? How does it work?
2. How is memory managed in Java (GC, heap, stack)?
3. Explain class loading process.
4. What is reflection?
5. What are enums and how are they useful?
6. What Is CAS?
7. When will you use AtomicReferences?
8. Explain Testing with Mockito or JUnit?
9. What is the difference between a mock and spy bean?
10. What’s an Observable?
11. What is a S3?
12. How to access S3?
12. Kafka
1. What is Apache Kafka?
2. What are the main components of Kafka?
3. What is a Kafka Topic and Partition?
4. How does Kafka ensure fault tolerance?
5. What is the role of Zookeeper in Kafka?
6. What is a Kafka Consumer Group?
7. What is Kafka’s delivery guarantee?
8. How does Kafka handle message retention?
9. How does Kafka ensure high throughput?
[Link] are Kafka producers and how do they work?
[Link] Kafka’s ISR (In-Sync Replicas).
[Link] is Kafka Stream API vs Kafka Consumer API?
[Link] is Kafka Connect?
[Link] happens when a Kafka broker fails?
[Link] is log compaction in Kafka?
[Link] would you scale Kafka for a high-throughput system?
[Link] is showing consumer lag. What do you do?
[Link] do you ensure message ordering in Kafka?
[Link] do Kafka transactions work?
[Link] are some real-world use cases of Kafka?
1. Java Basics
What are the main features of Java?
1. Platform Independent
Java code is compiled into bytecode (.class files) that runs on the Java Virtual Machine (JVM).
"Write once, run anywhere" — the same bytecode can run on any platform with a compatible JVM.
2. Object-Oriented
Everything in Java is treated as an object (except primitives).
Emphasizes principles like encapsulation, inheritance, polymorphism, and abstraction.
4. Secure
Provides a secure runtime environment by:
Restricting access to memory.
Running code inside the JVM sandbox.
Eliminating pointer arithmetic.
Having features like classloaders, bytecode verification, and a security manager.
5. Robust
Emphasizes error handling via exceptions.
Automatic garbage collection to manage memory.
Strong type checking at compile time and runtime.
6. Multithreaded
Java has built-in support for multithreading, making it easy to build highly concurrent
applications.
The Thread class and [Link] package provide tools for concurrent programming.
7. High Performance
While not as fast as C/C++, Java’s performance is improved with Just-In-Time (JIT) compilers.
JVM optimizations make Java suitable for performance-critical applications.
8. Distributed
Java provides tools to build networked and distributed applications, e.g. using:
[Link] package (sockets, URLs)
RMI (Remote Method Invocation)
Web services, REST APIs (via Spring, etc.)
9. Dynamic
Java supports dynamic loading of classes during runtime.
Reflection and runtime polymorphism make it highly flexible.
Contains:
JRE (Java Runtime Environment)
Development tools: compiler (javac), debugger, JavaDoc, etc.
Use case: Needed by developers to write, compile, and run Java applications.
If you’re writing Java code, you need the JDK.
Contains:
JVM
Core Java libraries
Supporting files
Use case: Needed by users to run Java applications, but not to develop them.
JRE does not include the compiler (javac), so you can’t write or compile code with it.
Responsibilities:
Converts bytecode into machine-specific code.
Handles memory management, garbage collection, and security.
Ensures platform independence.
Use case: Every Java program runs inside a JVM, regardless of platform.
The JVM is what makes Java "Write Once, Run Anywhere" possible.
Hierarchy Summary:
JDK
└── JRE
└── JVM
== Operator
Purpose: Compares references (memory addresses) for objects.
Example:
String s1 = new String("hello");
String s2 = new String("hello");
[Link](s1 == s2); // false — different objects in memory
.equals() Method
Purpose: Compares contents (logical equality) of objects.
Defined in Object class, but often overridden in classes like String, Integer, List, etc. to
compare data meaningfully.
For strings, .equals() checks if the sequence of characters is the same.
Example:
String s1 = new String("hello");
String s2 = new String("hello");
[Link]([Link](s2)); // true — same content
Summary Table
Comparison == .equals()
Example result false for two new String("hi") true for two strings with same chars
Example:
class Person {
String name;
int age;
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != [Link]()) return false;
Person other = (Person) obj;
return age == [Link] && [Link](name, [Link]);
}
@Override
public int hashCode() {
return [Link](name, age);
}
}
Summary:
Condition Requirement
Summary
Breakdown:
public — so JVM can access it from anywhere.
static — so JVM can call it without creating an instance of the class.
void — it doesn’t return any value.
main — the name JVM looks for as the entry point.
String[] args — array of command-line arguments passed as strings.
fi
fi
2. OOP Concepts in Java
What are the SOLID Principles?
Example use: I split a large service class handling both DB queries and business logic into two
separate components — one for persistence, another for domain logic.
Example use: I used an interface and a base class to support multiple notification methods
(Email, SMS, Slack) without modifying the existing notification logic.
Example use: I split a large UserService interface into smaller ones (UserReader, UserWriter) to
ensure that consumers only implemented what they needed.
Example use: In a Spring Boot project, I injected services via interfaces and used dependency
injection, making it easier to swap implementations and mock services in tests.
• Design patterns are proven, reusable solutions to common problems in software design.
• They are like templates or best practices that help solve design challenges in a
consistent and efficient way.
• Not complete code — more like a blueprint you adapt to your needs.
CREATIONAL PATTERNS
Focus on how objects are created and instantiated.
Singleton Ensure only one instance of a class exists Logger, Con guration
Prototype Clone existing objects instead of creating new Creating copies of objects in game engines
ones
STRUCTURAL PATTERNS
Deal with object composition, how classes and objects are structured.
Adapter Bridge between incompatible interfaces Wrapping an old API to match a new interface
Decorator Add responsibilities to objects dynamically Adding features like encryption or logging to a
stream
Facade Provide a simpli ed interface to a complex [Link], Spring RestTemplate
subsystem
Proxy Control access to an object (e.g., for lazy Hibernate’s lazy-loaded entities
loading, security)
Composite Treat individual and group of objects File system trees: Files and Directories
uniformly
Bridge Decouple abstraction from implementation Remote controls for di erent TVs
Flyweight Share common object data to save memory Font character caching, game tiles
BEHAVIORAL PATTERNS
Deal with communication between objects, or how they interact over time.
Observer Notify multiple objects about state changes Event listeners, UI updates
Chain of Responsibility Pass request along a chain of handlers Servlet lters, exception handling
State Allow object to change behavior when TCP connection: Open, Closed, Listening
internal state changes
Template Method De ne the skeleton of an algorithm, defer Abstract classes in frameworks
steps to subclasses
Mediator Coordinate interaction between multiple Chatroom example: mediator between users
objects
Memento Save and restore object state (undo) Saving game state
Singleton [Link]()
4. Bytecode Verification
Before execution, the JVM verifies the bytecode:
• Ensures there are no illegal code operations.
• Protects against bytecode-level attacks or corruption.
• Fails if the class file is malformed or violates JVM rules.
6. Execution in JVM
• The native code runs on your OS and CPU via the JVM.
• The JVM runtime manages:
• Memory allocation (Heap, Stack)
• Garbage Collection
• Threading & synchronization
• Exception handling
• Security and sandboxing
Component Purpose
Example Timeline
1. You compile: javac [Link] → [Link]
2. You run: java MyApp
3. JVM starts, loads class, verifies bytecode.
4. Interpreter begins running main method.
5. JIT compiles parts to native code for performance.
6. GC manages memory during execution.
What is ACID?
Quick example:
• You transfer money between bank accounts.
• Atomicity: Either both debit and credit happen, or neither.
• Consistency: Total money remains the same, no negative balance.
fi
fi
fi
• Isolation: If two transfers run concurrently, they don’t corrupt balances.
• Durability: Once transfer confirmed, data won’t be lost even if power fails.
1. Encapsulation
Bundling data (fields) and methods that operate on the data into a single unit (class).
Hides internal object details and exposes only necessary parts via access modifiers (private,
public, protected).
Protects object integrity by restricting direct access to some components.
2. Inheritance
Mechanism where one class (subclass/child) inherits fields and methods from another class
(superclass/parent).
Enables code reuse and hierarchical classification.
Supports method overriding to customise behavior.
3. Polymorphism
Ability of objects to take multiple forms.
Two types:
Compile-time polymorphism (method overloading)
Runtime polymorphism (method overriding)
Allows the same interface to be used for different underlying data types.
4. Abstraction
Hiding complex implementation details and showing only essential features.
Achieved using abstract classes and interfaces.
Helps reduce programming complexity and increases efficiency.
Key Points:
Happens in the same class.
Parameters must be different.
Return type can be the same or different (but return type alone cannot distinguish overloads).
Example:
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
Key Points:
Happens in two classes in an inheritance hierarchy.
Method must have:
Same name
Same parameters
Same return type (or covariant)
The method in the subclass replaces (overrides) the method in the parent class.
Access modifier in the subclass cannot be more restrictive.
Example:
class Animal {
void sound() {
[Link]("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
void sound() {
[Link]("Dog barks");
}
}
Comparison Table
Analogy
• Compile-time polymorphism: Like choosing which tool to use before you start work.
• Runtime polymorphism: Like selecting the right tool while working, based on the situation.
this Refers to the current object (the instance of the class where the code is running).
Refer to current class instance variables:
class Car {
String model;
ff
ff
fi
Car(String model) {
[Link] = model; // distinguish between field and parameter
}
}
class Car {
Car() {
this("Default Model");
}
Car(String model) {
[Link](model);
}
}
class A {
void display() {
[Link]("Hello");
}
void callDisplay() {
helper(this); // passes current object
}
void helper(A obj) {
[Link]();
}
}
super keyword
Refers to the parent (superclass) object of the current object.
class Animal {
Animal(String name) {
[Link]("Animal: " + name);
}
}
class Dog extends Animal {
Dog() {
super("Dog"); // calls Animal constructor
}
}
class Animal {
void speak() {
[Link]("Animal speaks");
}
}
class Dog extends Animal {
void speak() {
[Link](); // calls parent method
[Link]("Dog barks");
}
}
Summary
class School {
private List<Student> students; // aggregation
🔄 Summary Table:
Example Dog extends Animal Car has Engine School has Students
3. Data Types and Memory
Di erence between int, Integer, and long.
int (primitive type) 32-bit signed primitive data type. Stores whole numbers from -2³¹ to 2³¹ -
1.
More memory-efficient and faster than wrapper classes.
Default value: 0
int a = 10;
Integer (wrapper class) A class that wraps the primitive int in an object.
Part of [Link] package. Used when you need an object (e.g., with collections like
List<Integer>).
Supports methods like parseInt(), compareTo(), etc.
Supports autoboxing/unboxing: automatic conversion between int and Integer.
Default value: 0L
long id = 123456789012345L;
Summary Table
Feature int Integer long
Autoboxing ❌ ✅ Yes ❌
What is autoboxing/unboxing?
Java provides a convenient way to convert between primitive types (int, char, etc.) and their
wrapper classes (Integer, Character, etc.). This is known as:
Autoboxing Automatically converting a primitive type into its corresponding wrapper class.
Example:
int num = 10;
Integer boxed = num; // autoboxing: int → Integer
Unboxing Automatically converting a wrapper class object back into its corresponding primitive
type.
Example:
ff
Integer boxed = 20;
int num = boxed; // unboxing: Integer → int
Why is it useful?
Allows you to use primitive values in places where objects are required (like in collections):
Performance Note:
Autoboxing creates new objects, which adds memory and CPU overhead.
In performance-critical code (e.g., inside loops), prefer primitives if possible.
Summary
Feature Description Example
What is the default value of a local variable? (Ans: Compilation error if uninitialized.)
Why?
Java does not assign default values to local variables (those declared inside methods,
constructors, or blocks).
This prevents bugs caused by assuming an uninitialized variable has a usable value.
int 0
boolean false
Object null
Explain stack vs heap memory?
Stack Memory
Memory used for method execution and local variables.
Follows LIFO (Last In, First Out) order.
Key characteristics:
Fast access
Automatic allocation/deallocation — memory is released when the method finishes
Stores:
Primitive variables (e.g., int, boolean)
References to objects (not the objects themselves)
Example:
void example() {
int x = 10; // stored in stack
String s = "Hi"; // reference in stack, object in heap
}
Heap Memory
Memory used to store objects and class variables (static fields).
Shared across all threads.
Key characteristics:
Slower access than stack
Managed by the Garbage Collector (GC)
Stores:
All objects (e.g., instances created with new)
Static variables
Example:
String s = new String("Hello"); // object in heap, reference in stack
Comparison Table
Feature Stack Heap
Stack Overflow:
Happens when the call stack gets too deep, usually from Infinite recursion(Excessive method
calls without returning)
Example:
public class StackOverflowExample {
public static void recurse() {
recurse(); // infinite recursion!
}
public static void main(String[] args) {
recurse();
}
}
Why?
Every method call adds a frame to the stack.
The stack has limited size (e.g., ~1MB by default), so repeated calls cause it to overflow.
OutOfMemoryError (Heap)
Happens when the heap memory is full and the Garbage Collector (GC) can't free up enough space.
Common causes:
Creating too many objects
Holding references unnecessarily (memory leak)
Loading large data sets into memory
Example:
import [Link].*;
public class OutOfMemoryExample {
public static void main(String[] args) {
List<int[]> memoryHog = new ArrayList<>();
while (true) {
[Link](new int[1_000_000]); // allocates ~4MB each loop
}
}
}
What happens:
This program keeps allocating large chunks of heap memory without releasing any.
Eventually, the JVM throws: Exception in thread "main" [Link]: Java heap
space
Examples:
int age = 25;
long bigNumber = 1_000_000_000L;
float pi = 3.14f;
double precisePi = 3.141592653589793;
char letter = 'A';
boolean isJavaFun = true;
Tips:
Use **float** for less precision (e.g., graphics), and **double** for more accurate math.
**int** is the default for whole numbers.
Add suffixes:
L for long: long id = 10000000000L;
f for float: float pi = 3.14f;
De nition Basic data types built into the Instances of classes (created using new)
language
Stored in Stack memory Heap memory (reference stored in stack)
Primitive Example:
int x = 5;
Object Example:
Integer y = [Link](5); // Object wrapper for int
String s = "Hello";
🧠 Interview-ready Summary:
“Primitive types in Java are the basic data types like int, boolean, and double — they are
stored on the stack and don’t have methods. Objects are instances of classes and are stored on
the heap, allowing method calls and more flexibility. Java also provides wrapper classes like
Integer and Double to bridge primitives with collections via autoboxing.”
1. Primitive Types:
• The value (like a number) is copied.
• Changes to the parameter don’t affect the original variable.
void changePrimitive(int x) {
x = 10;
}
int a = 5;
changePrimitive(a);
// a is still 5
🧠 Interview-ready Summary:
“Java is strictly pass-by-value. For primitives, the actual value is copied. For objects, the
value of the reference is copied, meaning we can modify the object's contents but not reassign
the original reference. So Java is not pass-by-reference — just pass-by-value of the reference.”
"In Java, everything is passed by value. For primitives, the actual value is passed, so changes
don’t affect the original. For objects, a copy of the reference is passed, so you can change the
object’s contents but not reassign the caller’s original reference."
4. Strings and Immutability
Why is String immutable in Java?
1. Security
Strings are widely used in security-sensitive contexts like usernames, passwords, file paths,
network connections.
Immutability ensures once created, the value can’t be changed, preventing malicious code from
altering critical data.
3. Thread Safety
Immutable objects are inherently thread-safe since their state can’t change.
Multiple threads can access the same String instance without synchronization.
4. Hashcode Caching
Strings are often used as keys in hash-based collections like HashMap.
The immutability ensures that the hashcode remains constant during the object's lifetime,
preventing bugs related to data retrieval.
It's a special memory area inside the heap where Java stores unique String literals.
When you create a String literal, Java checks the pool first:
If the String already exists, it returns the reference to that existing object.
If it doesn't exist, it creates a new String object in the pool and returns it.
Summary:
Concept Description
1. String
Immutable: Once created, its value cannot be changed.
Operations like concatenation create a new String object each time.
Stored in String Pool if created as literals.
Example:
String s = "hello";
s = s + " world"; // creates new String objects internally
2. StringBuilder
Mutable: Can change value without creating new objects.
Not thread-safe — no synchronization.
Faster than StringBuffer because of no synchronization overhead.
Use when you need to build or modify strings quickly in a single-threaded environment.
Example:
StringBuilder sb = new StringBuilder("hello");
[Link](" world");
[Link]([Link]()); // prints "hello world"
3. StringBuffer
Mutable: Like StringBuilder, but thread-safe.
All methods are synchronized.
ff
ff
Slower than StringBuilder due to synchronization overhead.
Use when you need to modify strings in a multi-threaded environment where thread safety is
required.
Example:
StringBuffer sbf = new StringBuffer("hello");
[Link](" world");
[Link]([Link]()); // prints "hello world"
Summary Table
Feature String StringBuilder StringBu er
Performance Slow for many modi cations Fast Slower due to sync
1. == Operator
Compares reference equality (i.e., do both variables point to the exact same object in memory?)
Returns true if both references point to the same String object, else false.
2. .equals() Method
Compares content equality (i.e., do both Strings have the same sequence of characters?)
Returns true if contents are equal, regardless of whether they are the same object.
ArrayList vs LinkedList
Feature ArrayList LinkedList
Access Time (get/set) O(1) — direct index access O(n) — needs traversal
Memory Overhead Less (stores elements in contiguous More (stores data + 2 pointers per node)
array)
Iteration Speed Faster (better cache locality) Slower due to node traversal
Quick Example:
ArrayList<Integer> arrList = new ArrayList<>(); // ArrayList example
[Link](10);
int val = [Link](0); // fast access
1. Basic Structure
HashMap stores key-value pairs.
Internally, it uses an array of buckets.
Each bucket holds a linked list or a balanced tree (since Java 8) of entries (key-value pairs).
2. Hashing
When you put a key-value pair, HashMap:
Calls [Link]() to get an integer hash code.
Applies a hash function (usually a bitwise operation) to spread the hash codes evenly.
Computes the index in the bucket array: index = hash % array_length (actually using
bitmasking for power-of-two sized arrays).
3. Handling Collisions
Multiple keys can hash to the same bucket index (collision).
Initially, entries in a bucket are stored as a linked list.
Since Java 8, if the list gets too long (over 8 entries), it’s converted to a balanced tree
(red-black tree) to optimize lookup time from O(n) to O(log n).
6. Resizing
When the number of entries exceeds the load factor threshold (default 0.75), the HashMap
resizes:
Creates a new, larger bucket array (usually double the size).
Rehashes all existing entries to new buckets.
This helps maintain efficient O(1) average access time.
Summary Table
Aspect Details
Quick Visual:
sql
CopyEdit
[Bucket Array]
|-- Bucket 0 → (key1,value1) → (key9,value9)
|-- Bucket 1 → (key2,value2)
|-- Bucket 2 → null
|-- Bucket 3 → (key3,value3) → (key11,value11) → ... (list/tree)
...
Ordering No guaranteed order Sorted order (by natural Insertion order (or access
ordering or Comparator) order if con gured)
Underlying Data Structure Hash table (array + linked list/ Red-Black tree (self- Hash table + doubly linked
tree) balancing BST) list
Performance (get/put) O(1) average, O(n) worst case O(log n) O(1) average, O(n) worst case
ff
fi
Null keys/values Allows one null key, multiple No null keys, allows multiple Allows one null key, multiple
null values null values null values
Use case Fast lookup without order Sorted map needed Maintain insertion/access
requirement order
Quick explanations:
HashMap
Fast, unordered map.
Good default choice for most use cases.
No order guarantee when iterating keys or entries.
TreeMap
Keeps keys in sorted order.
Uses a Red-Black tree, so operations take O(log n).
Useful when you need sorted traversal or range queries.
LinkedHashMap
Maintains insertion order (or access order if accessOrder=true).
Slightly slower than HashMap due to maintaining a linked list.
Useful for caches or when order matters.
Example:
Map<String, Integer> hashMap = new HashMap<>();
Map<String, Integer> treeMap = new TreeMap<>();
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
[Link]("c", 3);
[Link]("a", 1);
[Link]("b", 2);
[Link]("c", 3);
[Link]("a", 1);
[Link]("b", 2);
[Link]("c", 3);
[Link]("a", 1);
[Link]("b", 2);
HashSet vs TreeSet
Feature HashSet TreeSet
Null Elements Allows one null element Does not allow null element
Use Cases Fast lookup, unique elements without Sorted unique elements with order
order
HashSet
Unordered collection of unique elements.
Fast insertion, deletion, and lookup.
Great when order does not matter but you want to ensure no duplicates.
TreeSet
Stores elements in sorted order.
Implements NavigableSet, so supports operations like first(), last(), headSet(), tailSet().
Use when you need a sorted set or range-based operations.
Example:
Set<String> hashSet = new HashSet<>();
[Link]("banana");
[Link]("apple");
[Link]("orange");
[Link]("HashSet: " + hashSet); // Order unpredictable
When to Use
Scenario Use HashSet Use TreeSet
Behavior on Concurrent Modi cation Throws Does not throw exception; works on a
ConcurrentModi cationException if the copy of the collection
collection is modi ed after iterator
creation (except via iterator’s own
remove() method)
fi
fi
fi
Example Collections Collections like ArrayList, HashMap, Collections from [Link]
HashSet (from [Link]) package, like CopyOnWriteArrayList,
ConcurrentHashMap
Use case Used when you want to detect Used in concurrent environments
concurrent modi cation bugs needing safe iteration
Example:
List<Integer> list = new ArrayList<>([Link](1, 2, 3));
for (Integer num : list) {
[Link](4); // Throws ConcurrentModificationException (fail-fast)
}
Vs
When to Use
Ideal for read-heavy, write-light workloads.
Useful when you want safe iteration without explicit synchronization.
fi
Examples:
Event listeners
Caches with rare updates
Maintaining lists of subscribers in multi-threaded apps
Example
Thread-safe without locks for reads Expensive memory and CPU on writes
Iterators never throw CME Not suitable for frequent modi cations
Overview
A thread-safe, high-performance implementation of the Map interface.
Designed for high concurrency with minimal contention.
Allows concurrent read and write operations without locking the entire map.
3. Data Structure
Uses a hash table with buckets (bins).
Each bin contains a linked list or, if large enough, a balanced tree (like HashMap).
Supports safe concurrent access to buckets.
Key Features
Concurrent Reads: No locking needed; very fast.
fi
Concurrent Writes: Lock only a small part (bin/node), not the whole map.
Size Estimation: Provides approximate size quickly without locking entire map.
No null keys or values allowed (unlike HashMap).
Example
When to Use
Highly concurrent environments with lots of reads and writes.
Applications like web servers, caches, real-time analytics.
Where thread safety and performance are critical.
Summary Table
Feature ConcurrentHashMap HashMap (not thread-safe)
Thread Safety Designed for use in concurrent Not thread-safe; requires external
environments without extra synchronization for safe concurrent use
synchronization
Performance Allows concurrent modi cations with Detects modi cations immediately but
minimal blocking requires locking for thread safety
Example (ConcurrentHashMap)
Iterator<String> it = [Link]().iterator();
[Link]("C", 3); // Modify map during iteration — no exception!
while ([Link]()) {
[Link]([Link]()); // May or may not include "C"
}
may or may not include the newly added element "C" when iterating over a ConcurrentHashMap’s
keySet iterator is because of the weakly consistent nature of its iterator.
Here’s why:
When you create an iterator from a ConcurrentHashMap (like [Link]().iterator()), the
iterator gets a snapshot view of the map’s internal structure at some point in time.
Because ConcurrentHashMap is designed for concurrency without locking the whole map,
modifications made after the iterator is created are allowed and don’t cause exceptions.
However, the iterator does not guarantee that these later modifications (like [Link]("C", 3))
will be immediately visible in the iteration.
So, when you call [Link](), the iterator may or may not return the newly added key "C". It
depends on whether that part of the internal data structure was already visited or incorporated
when the snapshot was taken.
Summary
May or may not include "C" = iterator reflects some changes but not guaranteed to see all
concurrent updates.
This makes iterating over ConcurrentHashMap safe without locks but without strong consistency
guarantees.
6. Exception Handling
Di erence between Checked and Unchecked exceptions.
When to Use For recoverable conditions, or expected For programming errors, bugs, or
exceptional situations unexpected conditions
Compiler Enforcement Yes, compiler enforces handling No, compiler does not enforce handling
Checked Exceptions force you to handle or declare them, encouraging you to think about error
handling.
Unchecked Exceptions usually indicate programming mistakes (like accessing a null object), which
should be fixed rather than caught.
Example:
// Checked Exception example
public void readFile() throws IOException {
// Must handle or declare IOException
FileReader file = new FileReader("[Link]");
}
The finally block in Java is used to execute code that must run regardless of whether an
exception is thrown or caught.
Example:
try {
// Code that may throw an exception
int result = 10 / 0;
fi
ff
fi
} catch (ArithmeticException e) {
[Link]("Caught exception: " + e);
} finally {
[Link]("This always runs!");
}
Output:
Caught exception: [Link]: / by zero
This always runs!
Key points:
finally runs whether or not an exception occurs.
Useful for cleaning up resources (closing streams, freeing connections).
If both try and finally have return statements, the one in finally will override the return from
try.
Yes, you can catch multiple exceptions in a single catch block in Java (starting from Java 7)
using the multi-catch syntax.
try {
// code that might throw IOException or SQLException
} catch (IOException | SQLException e) {
[Link]("Caught exception: " + e);
}
Key points:
Reduces code duplication when you want to handle different exceptions the same way.
The exceptions must not have a subclass-superclass relationship.
The exception variable (e) is effectively final (can't be reassigned inside the catch).
Usage
if (![Link]()) {
throw new DatabaseUnavailableException("Cannot connect to DB.");
}
Best Practices
Inherit from the correct type: Exception vs RuntimeException.
Always include a constructor that accepts a message (and optionally a cause).
Use meaningful names to describe the error clearly.
Document what causes the exception and how to handle it.
7. Concurrency and Multithreading
What is the di erence between Runnable and Thread?
Inheritance Can be implemented alongside other Cannot extend another class if you
classes (no inheritance restriction) extend Thread
How to Use Implement Runnable and pass to a Extend Thread and override run()
Thread object
Reusability Better — separates task logic from Less reusable — task logic and thread
thread management code are coupled
Flexibility More exible — can share the same Less exible — tied to a single thread
Runnable across threads instance
This approach decouples the task logic (MyTask) from how the thread is managed.
This works, but it's less flexible because you can’t extend another class.
It works by acquiring a lock (monitor) on an object or class before entering the synchronized
section.
3. Synchronized Block
public void update() {
synchronized (this) {
// critical section
}
}
Allows you to lock on any object (including this or a separate lock object).
More flexible and efficient than synchronizing the entire method.
class Counter {
int count = 0;
If two threads call increment() at the same time, count may get corrupted.
Fix with synchronization:
public synchronized void increment() {
count++;
}
Key Points
Synchronization prevents thread interference and memory consistency errors.
It introduces performance overhead due to locking.
Always use it only on critical sections, not entire methods if possible.
A race condition occurs in a multithreaded environment when two or more threads access shared
data at the same time, and the final result depends on the timing of their execution.
This can lead to unpredictable, inconsistent, or corrupt results.
If two threads run increment() simultaneously, both may read the same count, increment it, and
write back the same value — one increment gets lost.
1. Use synchronized
Synchronize critical sections so that only one thread can access them at a time.
public synchronized void increment() {
count++;
}
🔄 Basic Usage:
import [Link];
ReentrantLock lock = new ReentrantLock();
public void doSomething() {
[Link](); // Acquires the lock
try {
// Critical section (only one thread can be here)
} finally {
[Link](); // Always release in finally block
}
}
Interview Summary:
"ReentrantLock is an explicit lock in Java that provides more flexible locking than
synchronized. It supports reentrancy, try-locks with timeouts, interruptible waits, and
condition variables. It’s useful when you need more control over lock behavior in multithreaded
applications."
Volatile Keyword
What It Does:
Ensures visibility of changes to variables across threads.
Tells the JVM: “Do not cache this variable; always read it from main memory.”
Example:
private volatile boolean running = true;
public void stop() {
running = false;
}
Without volatile, other threads may cache running and not see the updated value immediately.
Summary
Feature volatile AtomicInteger (and others)
wait() vs sleep()
Feature wait() sleep()
Used for Thread coordination (e.g., producer- Pausing execution (e.g., delay)
consumer)
Releases lock? ✅ Yes, it releases the monitor lock ❌ No, it keeps any held locks
When to Use
Use sleep() when you just want to pause execution.
Use wait() when you're coordinating threads — like one thread waiting for another to produce
data.
fi
fl
ff
Explain ExecutorService and thread pools.
What is ExecutorService?
ExecutorService is part of the [Link] package. It’s a higher-level API for
managing and controlling thread execution compared to manually creating Thread objects.
Instead of manually starting threads, you:
Submit tasks (Runnable or Callable)
Let the service manage the thread lifecycle
Benefits:
Better performance: Reuses threads, reducing object creation/destruction overhead.
Control: Limits the number of concurrent threads.
Resource management: Avoids running too many threads and exhausting system resources.
Method Description
Callable + Future
If you want the task to return a result:
[Link](); // graceful
// OR
[Link](); // forceful
fi
Summary
ExecutorService = thread manager
Thread pool = pre-created threads reused for tasks
Runnable = no return; Callable = returns value
Use Future to get result or check task status
Always shut down the executor when done
ExecutorService is a high-level interface for executing asynchronous tasks. It internally uses a
thread pool to manage thread reuse and efficiency. So while a thread pool is the underlying
mechanism, ExecutorService is the abstraction that developers interact with to manage concurrent
execution."
8. Java Keywords and Modi ers
What is the di erence between nal, nally, and nalize()?
final (Keyword)
Used to declare constants, prevent overriding, or reassignment.
Use Cases:
Final variable: Cannot be reassigned.
final int x = 10;
finally (Block)
Used in exception handling to guarantee execution of a block of code (usually for cleanup)
regardless of whether an exception occurs.
Example:
try {
int result = 10 / 2;
} catch (ArithmeticException e) {
[Link]("Error!");
} finally {
[Link]("This will always run.");
}
Example:
@Override
protected void finalize() throws Throwable {
[Link]("Object is being garbage collected");
}
⚠ Deprecated since Java 9 and removed in later versions — it's unreliable and discouraged.
Summary Table
Keyword Purpose Called by Use Case Example
nally Always executes cleanup JVM (after try/catch) Release resources (e.g. close
code le)
fi
fi
fi
ff
fi
fi
fi
fi
nalize() Run before object is garbage JVM (GC) [Deprecated] Rarely used, bad practice
collected
Why?
The final keyword in Java is used to prevent method overriding.
But constructors are not inherited, and therefore cannot be overridden.
Since there's no need to prevent overriding, marking a constructor final makes no sense — and
the compiler disallows it.
Error: Illegal modifier for the constructor; only public, protected, private, or default are
permitted.
🧠 Summary
synchronized ❌ No
The static keyword in Java means "belongs to the class, not to an instance." It can be used with
variables, methods, blocks, and nested classes.
Examples
1. Static Variable
class Example {
static int count = 0;
Example() {
count++;
}
}
count is shared among all instances.
Used for constants and shared counters.
2. Static Method
class MathUtils {
static int square(int x) {
return x * x;
}
}
// Usage
int result = [Link](5); // No object needed
Cannot access non-static (instance) variables or methods.
Common example: main() method is static.
3. Static Block
class Config {
static {
[Link]("Class loaded!");
}
}
Executes once when the class is first loaded.
Often used for static initialization.
Things to Remember
Static methods can't use this or super.
Static methods can't access non-static fields directly.
Summary
Use static for shared state or utility methods.
Avoid excessive use — it breaks OOP principles like encapsulation.
transient
Used with fields to exclude them from serialization.
When an object is serialized (converted to bytes), transient fields are skipped — their values
won’t be saved.
Useful for sensitive data (passwords) or fields that can be recalculated or aren’t needed in
serialized form.
Example:
class User implements Serializable {
private String username;
private transient String password; // won't be serialized
// constructors, getters, setters
}
volatile
Used with fields to ensure visibility of changes across threads.
Guarantees that when one thread updates a volatile variable, other threads see the latest value
immediately.
Does not guarantee atomicity for compound operations (like count++).
Example:
private volatile boolean running = true;
public void stop() {
running = false; // visible to other threads immediately
}
Summary
Modi er Purpose Use Case
Runnable only has void run() and can't return a result or throw checked [Link]<V>
has V call() that returns a value and can throw exceptions.
Example:
ExecutorService executor = [Link](2);
fi
fi
ff
Runnable runnableTask = () -> [Link]("Running");
Callable<String> callableTask = () -> {
[Link](1000);
return "Callable Result";
};
[Link](runnableTask);
Future<String> future = [Link](callableTask);
[Link]([Link]()); // prints "Callable Result"
[Link]();
Example:
ExecutorService executor = [Link](3);
[Link](() -> [Link]("Runnable Task"));
Future<String> future = [Link](() -> "Callable Task");
[Link]([Link]()); // prints "Callable Task"
[Link]();
API complexity Simple interface with get(), cancel() Rich API with many methods for functional-style async programming
ff
In short:
• Future is a basic way to get a result from an async task, but you have to block and wait
(get()), and it doesn’t support chaining.
• CompletableFuture is a powerful, flexible tool for asynchronous programming that lets you
compose, combine, and handle async tasks without blocking.
• Thread-safe means that code or data structures function correctly during simultaneous
execution by multiple threads.
• Without thread safety, threads can interfere with each other leading to bugs like lost
updates or inconsistent reads.
2. Synchronization
• Use the synchronized keyword to control access to critical sections.
public synchronized void increment() {
count++;
}
• Only one thread can execute a synchronized method/block at a time.
3. Explicit Locks
• Use Lock interface (e.g., ReentrantLock) for more flexible locking.
Lock lock = new ReentrantLock();
[Link]();
try {
// critical section
} finally {
[Link]();
}
• Allows features like try-lock, timed-lock, or interruptible lock acquisition.
4. Volatile Variables
• Declaring a variable volatile ensures visibility of changes across threads immediately.
private volatile boolean flag = false;
• Useful for flags or state checks, but does not guarantee atomicity.
5. Atomic Variables
• Use classes like AtomicInteger, AtomicBoolean for lock-free thread-safe operations.
AtomicInteger count = new AtomicInteger(0);
[Link]();
• Provides atomic read-modify-write operations without synchronization overhead.
6. Thread-safe Collections
• Use concurrent collections from [Link], e.g.:
◦ ConcurrentHashMap
◦ CopyOnWriteArrayList
◦ BlockingQueue
These are designed internally to handle concurrent access efficiently.
Summary
Synchronization Critical sections need exclusive access Simple, but can cause blocking
Thread Con nement Data only needed by one thread No synchronization needed
fi
fi
fi
fl
What’s the Lock interface?
Condition variables Only one per object Supports multiple Condition objects
Interview-friendly summary:
“The Lock interface is an advanced alternative to the synchronized keyword for thread
synchronization. It gives explicit control over locking, allowing features like tryLock, timed
lock waits, and interruptible locks. ReentrantLock is a popular implementation that I use when I
need more flexibility than synchronized provides.”
9. Interfaces vs Abstract Classes
Key di erences between interface and abstract class?
Purpose De nes a contract (methods to implement) Provides partial implementation and contract
Methods All abstract by default (Java 7 and earlier) Can have abstract and concrete methods
Since Java 8: default and static methods
allowed
Multiple Inheritance Supports multiple inheritance (a class can No multiple inheritance (a class can extend
implement multiple interfaces) only one abstract class)
Fields Only public static nal constants Can have instance variables, any access
modi er
Access Modi ers for Methods Methods are implicitly public Methods can have any visibility (public,
protected, private)
When to Use When you want to specify a contract for When you want to share code among closely
unrelated classes related classes
Quick Examples
Interface
interface Flyable {
void fly();
}
Abstract Class:
abstract class Bird {
void eat() {
[Link]("Eating");
}
abstract void fly();
}
Summary
Use interface to define capabilities or contracts without implementation.
Use abstract class to provide shared code and enforce some methods to be implemented.
Syntax Example:
interface Vehicle {
fi
fi
ff
fi
fi
void start();
default void stop() {
[Link]("Vehicle stopped.");
}
}
Key Points
Default methods are concrete.
Help maintain backward compatibility when interfaces evolve.
Classes can override default methods.
Interfaces can also have static methods (since Java 8), but those belong to the interface and
aren’t inherited.
Example:
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
public void fly() {
[Link]("Duck is flying");
}
public void swim() {
[Link]("Duck is swimming");
}
}
Can you extend multiple classes?
No! Java does NOT support multiple inheritance of classes — a class can extend only one class.
Example:
class A { }
class B { }
Summary
Feature Allowed?
Example:
@FunctionalInterface
interface Greeting {
void sayHello(String name);
}
Characteristic Description
Stream Operations:
Method references are a neat shortcut in Java to use existing methods as lambda expressions
without writing the lambda code explicitly.
Examples
1. Static Method Reference
List<Integer> nums = [Link](3, 1, 4, 2);
[Link]()
.max(Integer::compare)
.ifPresent([Link]::println);
4. Constructor Reference
Supplier<List<String>> listSupplier = ArrayList::new;
List<String> list = [Link]();
When to Use?
When a lambda just calls an existing method.
Makes code cleaner and easier to read.
Di erence between map() and atMap()?
map() vs flatMap()
Aspect map() atMap()
Input Takes a function that transforms each Takes a function that transforms each
element to another object (can be any element into a Stream (or another at
type) structure)
Output Stream of transformed elements (e.g., Flattens multiple Streams into a single
Stream<R>) Stream (Stream<R>)
Use Case When you want to apply a one-to-one When you want to apply a one-to-many
transformation on elements transformation and atten the result
Resulting structure Nested streams if you return a Stream A single attened stream with all
inside map() elements combined
Example: map()
Suppose you have a list of strings and want their lengths:
List<String> words = [Link]("apple", "banana", "cherry");
List<Integer> lengths = [Link]()
.map(String::length) // one-to-one mapping: String -> Integer
.collect([Link]());
[Link](lengths); // Output: [5, 6, 6]
Example: flatMap()
Suppose you have a list of sentences and want all the words in a single stream:
List<String> sentences = [Link]("hello world", "java streams");
List<String> words = [Link]()
.flatMap(sentence -> [Link]([Link](" "))) // one-to-many: String ->
Stream<String>
.collect([Link]());
[Link](words); // Output: [hello, world, java, streams]
Summary
Use map() for simple transformations.
Use flatMap() when your transformation returns a stream or collection that needs to be flattened
into a single stream.
The Optional class in Java helps you handle nullable values safely and avoid the dreaded
NullPointerException.
What is Optional?
A container object that may or may not contain a non-null value.
Introduced in Java 8 to represent optional values explicitly.
Forces you to think about the absence of a value instead of blindly using null.
2. Accessing Value
Check if value is present
if ([Link]()) {
[Link]([Link]());
}
Or use ifPresent()
[Link](val -> [Link](val));
Example Usage:
public Optional<String> findNameById(int id) {
if (id == 1) {
return [Link]("Alice");
} else {
return [Link]();
}
}
Summary
Feature Description
All three are stereotype annotations and specializations of @Component. They mark classes as
Spring-managed beans, and Spring will auto-detect and register them with the ApplicationContext.
Example:
@Component
public class GenericBean {}
@Service
public class PaymentService {}
@Repository
public class PaymentRepository {}
Dependency Injection (DI) is a design pattern used in Spring (and other frameworks) to manage
object dependencies.
Instead of a class creating its own dependencies (tight coupling), they are "injected" from the
outside — typically by the Spring container.
Analogy:
Imagine you're hiring a driver:
• Without DI: You build the car inside the driver class.
• With DI: You give the driver a car — the driver just uses it.
@Component
public class Car {
private final Engine engine;
@Autowired
public Car(Engine engine) {
[Link] = engine;
}
Testability Advantage:
Car car = new Car(mockEngine); // Easy to test with mocks!
You can easily mock the Engine and pass it to Car — no need for Spring context in a unit test.
1. @SpringBootApplication
Combines 3 key annotations:
• @Configuration – marks the class as a source of bean definitions
@RestController
@RequestMapping Any
@GetMapping GET
@PostMapping POST
@PutMapping PUT
@DeleteMapping DELETE
Example:
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { ... }
“It defines which URL and HTTP method should call which method in the controller.”
@Autowired
• Tells Spring to automatically inject a bean
@Autowired
private UserService userService;
“Spring looks for a bean of type UserService and injects it here.”
Annotation Purpose
@Component Generic Spring bean
@Service Business logic layer
@Repository Data access layer; adds exception translation
@Controller Web MVC controller (returns views)
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
@Value and @ConfigurationProperties
@Value("${[Link]}")
private String appTitle;
Or bind whole config objects:
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String title;
private int version;
}
@Profile
• Enables beans or configs only in specific environments (dev, prod, test)
@Profile("dev")
@Bean
public DataSource devDataSource() { ... }
Example:
@Configuration
@Profile("dev")
public class DevDataSourceConfig {
@Bean
public DataSource dataSource() {
// dev DB config
}
}
Activate a profile:
yaml
CopyEdit
spring:
profiles:
active: dev
fi
What is the context in Spring?
The Spring ApplicationContext is a container that manages beans lifecycle and dependency
injection.
It acts as a central interface for configuration and manages the creation, wiring, and lifecycle
of Spring-managed objects.
Provides services like:
• Bean factory
• Event propagation
• Resource loading
• Internationalization support
12. Miscellaneous
What is serialization? How does it work
Serialization is a fundamental concept in Java for converting objects into a format that can be
easily stored or transmitted. Here’s a breakdown:
What is Serialization?
Serialization is the process of converting an object into a byte stream.
This byte stream can be saved to a file, sent over a network, or stored in a database.
The opposite process, deserialization, reconstructs the object from the byte stream.
Simple Example:
import [Link].*;
class Person implements Serializable {
private static final long serialVersionUID = 1L; // version control
String name;
int age;
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("[Link]"))) {
Person deserializedPerson = (Person) [Link]();
[Link]([Link] + ", " + [Link]);
} catch (IOException | ClassNotFoundException e) {
[Link]();
}
}
}
Important Points:
serialVersionUID: Used for versioning serialized classes. If changed between serialization and
deserialization, you get InvalidClassException.
Transient fields: Marked with transient keyword and not serialized.
If a non-serializable object is referenced inside a serializable class, serialization will fail
unless it’s marked transient.
1. Heap Memory
Where all objects and instance variables live.
Shared among all threads.
Divided into:
Young Generation (Eden + Survivor spaces) — newly created objects.
Old (Tenured) Generation — long-lived objects promoted here.
Permanent Generation (or Metaspace in Java 8+) — stores class metadata, interned
strings.
2. Stack Memory
Each thread has its own stack.
Stores primitive local variables, method call frames, and references to objects on the heap.
Supports method invocation and return.
Stack memory is LIFO (Last In, First Out).
GC process:
Mark: Identify reachable objects.
Sweep: Remove unreachable objects.
Compact: Optional step to reduce fragmentation.
Summary Table
Memory Area Purpose Lifetime Shared?
Heap Objects and instance Until GC removes Shared
variables
Stack Local primitives, method calls Until method ends Thread-local
Additional Notes
Finalizers (using finalize() method) are discouraged; use try-with-resources or explicit cleanup
instead.
You can suggest GC via [Link](), but it’s only a hint. Memory leaks can happen if references
unintentionally persist (e.g., static collections).
The class loading process in Java is how the JVM loads class files into memory so that your Java
program can use them at runtime. Here’s a clear breakdown:
1. Loading
JVM locates the .class file (from disk, network, or other sources).
Reads the bytecode and creates an in-memory Class object.
Uses ClassLoader to do this.
2. Linking
Three sub-steps here:
Verification: Checks bytecode correctness to ensure it doesn't violate JVM rules.
Preparation: Allocates memory for static variables and sets them to default values.
Resolution: Replaces symbolic references with direct references (resolves other classes,
methods).
3. Initialization
Executes static initializers and static blocks in the class.
Initializes static variables with their explicit values.
Bootstrap ClassLoader Core Java API classes ([Link]), part of JVM itself
Summary
What is re ection?
Reflection is a feature in Java that allows a program to inspect and manipulate its own
structure (classes, methods, fields) at runtime.
It lets you dynamically examine classes, interfaces, fields, and methods, even if you don't know
their names at compile time.
Also enables you to invoke methods, access fields, and create objects dynamically.
Simple Example:
Class<?> clazz = [Link]("[Link]"); // Load class dynamically
Method sizeMethod = [Link]("size"); // Get method info
Object listInstance = [Link]().newInstance(); // Create instance
int size = (int) [Link](listInstance); // Invoke method dynamically
[Link]("Size: " + size); // Output: Size: 0
Important Notes
Reflection bypasses normal access control checks, so you can access private members (with
setAccessible(true)).
It has performance overhead compared to direct calls.
Can lead to security risks if misused.
Use reflection sparingly and only when necessary.
Security Concerns:
Accessing Private Members: Reflection can access and modify private fields/methods, potentially
breaking encapsulation.
Bypassing Security Managers: Without proper security policies, reflection can be exploited to
access sensitive data.
Injection Attacks: Malicious input can cause unexpected reflection calls if not properly
validated.
Performance Overhead: Excessive reflection use can degrade performance.
Best Practices:
Restrict reflection use to trusted code.
Avoid reflection when alternatives exist.
Use SecurityManager or Java modules system to limit reflective access.
Example
@Retention([Link])
@interface MyAnnotation {
String value();
}
@MyAnnotation("ExampleClass")
class Example {}
public class Test {
public static void main(String[] args) {
Class<Example> clazz = [Link];
if ([Link]([Link])) {
MyAnnotation annotation = [Link]([Link]);
[Link]([Link]()); // Output: ExampleClass
}
}
}
What are enums and how are they useful?
Usage:
Day today = [Link];
if ([Link]()) {
[Link]("Time to work!");
} else {
[Link]("Relax!");
}
Benefits
• No blocking/locks → Better performance and avoids deadlocks.
• High throughput in multi-threaded environments.
Limitations
1. Spin loops: CAS may retry many times if there's contention.
2. ABA Problem: If value changes from A → B → A again, CAS thinks nothing changed
(solved using stamps or version numbers).
3. Complex logic: CAS is best for simple updates — complex changes may require
other synchronization.
Java Example:
import [Link];
public class Example {
public static void main(String[] args) {
AtomicInteger counter = new AtomicInteger(5);
// Try to change 5 to 10
boolean updated = [Link](5, 10);
Note
AtomicReference only helps with atomic reference changes — not with modifying fields
inside the object. If the object is mutable, further synchronization might still be
needed.
What’s an Observable?
Key Points:
• It emits 0 or more items asynchronously.
• Observers can receive:
◦ Next items (data)
◦ Error notifications
◦ Completion notification (stream ended)
• Supports operators to transform, filter, combine data streams.
Simple analogy:
Imagine a news feed that pushes articles to subscribers as they come in — the news feed is the
Observable, and you are the subscriber receiving updates.
[Link](
item -> [Link]("Received: " + item),
error -> [Link]("Error: " + error),
() -> [Link]("Done!")
);
Output:
makefile
CopyEdit
Received: Hello
Received: World
Done!
Interview-friendly summary:
“An Observable is a stream of data or events that can emit multiple values asynchronously to
subscribers. It’s a key concept in reactive programming, allowing us to write non-blocking,
event-driven applications that can easily handle streams of data like user inputs, server
responses, or sensor data.”
• Mock:
◦ A fake object that simulates the behavior of real objects.
ff
◦ Does not execute real methods unless explicitly specified.
◦ Used to isolate tests from dependencies.
• Spy:
◦ Wraps a real object.
◦ Real methods are called unless stubbed.
◦ Useful when you want to test part of the behavior while still using the real
object.
De niti A mock is a test double that simulates a complete object. You A spy wraps a real object and partially mocks it — real methods are
on de ne its behavior explicitly. called unless explicitly stubbed.
Use When you want to completely replace a dependency in your When you want to verify interactions but still use real method logic,
case test. or stub some methods only.
Created using
Creatio Created using [Link](realObject) or @Spy
n
[Link]([Link]) or @Mock
annotation.
annotation.
Exampl Mock a service to return prede ned responses without Spy on a list to verify method calls but still allow real add()
e running real code. behavior.
Spy
List<String> realList = new ArrayList<>();
List<String> spyList = [Link](realList);
[Link]("Hello");
[Link](spyList).add("Hello");
[Link]([Link]()); // prints 1 because real method called
Interview-friendly summary:
“A mock is a fully simulated object where you define all behavior, useful for isolating tests. A
spy wraps a real object and lets you call real methods unless you stub them, allowing partial
mocking. In Spring Boot tests, you use @MockBean to replace beans and @SpyBean to partially mock
existing beans.”
fi
fi
fi
What is a S3?
Amazon Simple Storage Service (S3) is a highly scalable, durable, and secure object storage
service provided by AWS.
Key Points:
• Stores objects (files, images, videos, backups, etc.) in buckets.
• Objects can be any size, from kilobytes to terabytes.
• Designed for 99.999999999% (11 nines) durability — meaning your data is very safe.
• Offers high availability and scalability — you don’t need to worry about storage limits.
• Supports fine-grained access control, encryption, and lifecycle policies.
• Commonly used for:
◦ Static website hosting
◦ Backup and restore
◦ Data archiving
◦ Big data analytics input/output
◦ Media storage
Simple analogy:
Think of S3 as a cloud hard drive where you store files, accessible from anywhere via the
internet.
Basic structure:
Concept Description
Accessing Amazon S3 (Simple Storage Service) typically involves using AWS SDKs to interact with
buckets and objects (files). Here's a clear guide to help you explain or implement S3 access in
Java — perfect for your interview prep.
1. Set Up AWS SDK for Java
Add AWS SDK dependency (Maven example):
<dependency>
<groupId>[Link]</groupId>
<artifactId>s3</artifactId>
<version>2.x.x</version>
</dependency>
3. Create S3 Client
import [Link].s3.S3Client;
import [Link];
S3Client s3 = [Link]()
.region(Region.US_EAST_1)
.build();
4. Basic Operations
a) List Buckets
[Link]().buckets().forEach(bucket -> {
[Link]([Link]());
});
b) Upload a File
import [Link];
import [Link];
[Link](putReq, [Link]([Link]("[Link]")));
c) Download a File
import [Link];
import [Link];
[Link](getReq, [Link]("[Link]"));
5. Best Practices
• Use IAM roles for AWS resources to avoid embedding credentials.
• Handle exceptions like S3Exception.
• For large files, use multipart uploads.
• Use async client for non-blocking operations if needed.
• distributed streaming platform used for building real-time data pipelines and streaming
applications.
• designed to be fault-tolerant.
• high-throughput.
• horizontally scalable.
• based on a publish-subscribe messaging system
• stores streams of records in categories called topics.
Kafka replicates partitions across multiple brokers. Each partition has a leader and one or
more followers. If the leader fails, a follower takes over, ensuring no data is lost.
Zookeeper manages:
• Metadata about brokers and topics
• Leader election for partitions
• Cluster configuration and membership
Note: Kafka 2.8+ supports KRaft mode, which allows Kafka to run without Zookeeper.
A consumer group is a set of consumers that work together to consume data from a topic. Each
partition is consumed by only one consumer in the group. This enables load
balancing and parallel processing.
7. What is Kafka’s delivery guarantee?
Kafka retains messages for a configurable period (default 7 days) or until a specified size
limit is reached, even if they are consumed. This makes Kafka suitable for replaying data.
Kafka producers push data to topics. They can choose which partition to write to using:
• A key-based partitioner (same key goes to the same partition)
• A round-robin approach (default when no key is specified)
The ISR is the set of replicas that are fully caught up with the leader’s data. Kafka only
considers messages “committed” when they are written to all ISRs, ensuring durability.
• Consumer API: Lets you manually consume and process Kafka messages.
• Streams API: High-level abstraction for building stream processing applications with features
like windowing, joins, and stateful operations.
Kafka Connect is a framework for connecting Kafka with external systems like databases or file
systems using prebuilt connectors (e.g., JDBC, HDFS, Elasticsearch).
14. What happens when a Kafka broker fails?
Log compaction allows Kafka to retain only the latest value for each key. This is useful for
restoring state after a failure and for use cases like changelogs.
Message ordering is guaranteed within a partition. To ensure ordering for related messages,
always produce them with the same key so they land in the same partition.
Kafka transactions allow atomic writes across multiple partitions and topics. A producer can
send messages as part of a transaction using the initTransactions() and commitTransaction()
APIs, ensuring exactly-once semantics.