Interview
Interview
OOPS
1. Encapsulation
2. Abstraction
3. Inheritance
4. Polymorphism
Encapsulation
Encapsulation means binding data and methods that operate on that data into a single unit, typically a
class, and restricting direct access to some of the object's components.
private fields
public getters and setters
Example:
class BankAccount {
private double balance; // data hidden
Here:
Why important?
Abstraction means hiding implementation details and exposing only essential functionality.
abstract classes
interfaces
interface Payment {
void pay(double amount);
}
Whether it is UPI
Credit card
Net banking
Why important?
Reduces complexity.
Allows flexibility.
Encourages loose coupling.
Inheritance
Inheritance means one class acquires properties and behavior of another class.
class Vehicle {
void start() {
[Link]("Vehicle starting");
}
}
Why important?
Code reuse.
Logical hierarchy.
Supports polymorphism.
Polymorphism
class Animal {
void sound() {
[Link]("Animal sound");
}
}
Abstraction and Encapsulation are both OOP principles, but they solve different problems.
Abstraction is about hiding implementation details and exposing only the essential functionality to the
user.
It focuses on what an object does, not how it does it.
Encapsulation, on the other hand, is about binding data and methods together and restricting direct access
to the object’s internal state.
It focuses on data protection.
Method Overloading and Method Overriding are two ways to achieve polymorphism in Java, but they
differ in when and how they are resolved.
Method Overloading
Method overloading means defining multiple methods with the same name in the same class, but with
different parameter lists.
Number of parameters, or
Type of parameters, or
Order of parameters
Method Overriding
Method overriding means a subclass provides a specific implementation of a method that is already defined
in its parent class.
Conditions:
Inheritance
A subclass inherits properties and behavior from a parent class using the extends keyword.
It promotes code reuse but creates tight coupling between parent and child
Composition
It promotes loose coupling and is generally preferred over inheritance in many real-world designs.
Abstract class and Interface are both used to achieve abstraction in Java
Abstract Class
It is used when there is a common base class with shared state or behavior.
Interface
It contains:
Key Differences
Multiple inheritance means a class inheriting from more than one parent class.
In Java, multiple inheritance of classes is not supported, meaning a class cannot extend more than one class.
If two parent classes have a method with the same name, and the child inherits both, the compiler will not know
which method to execute.
In summary:
Java does not support multiple inheritance of classes to avoid the diamond problem, but it achieves multiple
inheritance using interfaces.
8. What is JVM?
JVM stands for Java Virtual Machine.
It is a part of the Java Runtime Environment (JRE) that is responsible for executing Java bytecode and
converting it into machine-level instructions for the underlying operating system.
In simple terms, JVM enables the principle of “Write Once, Run Anywhere
JVM is the runtime engine that executes Java bytecode, manages memory, and ensures platform independence.
JDK, JRE, and JVM are three different components of the Java ecosystem, each serving a specific
purpose.
It contains:
JVM
Core libraries (like [Link], [Link], etc.)
Supporting files required at runtime
JRE is used only for running Java applications, not for developing them.
It contains:
JRE
Development tools such as:
o javac (compiler)
o javadoc
o jdb (debugger)
o Other development utilities
JVM architecture defines how the Java Virtual Machine loads, stores, and executes Java programs.
The Class Loader is responsible for loading .class files into memory.
a) Loading
b) Linking
c) Initialization
1) Method Area
2) Heap Area
3. Execution Engine
It has:
Interpreter
Garbage Collector
Flow of Execution
In summary:
JVM architecture consists of the Class Loader, Memory Areas, and Execution Engine, which together load,
manage, and execute Java programs efficiently and securely.
Heap and Stack are two different memory areas in JVM used for different purposes
Stack Memory
Method execution
Local variables
Method parameters
Stack frames
Faster access
Automatically managed
Limited in size
Not shared between threads
Heap Memory
Objects
Instance variables
Arrays
It was introduced in Java 8, replacing the older PermGen (Permanent Generation) space.
It stores information about the class definitions, not the objects themselves.
Objects are stored in the Heap.
A memory leak in Java occurs when objects that are no longer needed are still referenced, so the
Garbage Collector cannot remove them from the heap.
Even though Java has automatic garbage collection, memory leaks can still happen due to improper object
reference management.
If an object is still reachable through a reference, the Garbage Collector will not remove it.
Example:
Here, objects keep getting added and never removed, so memory keeps increasing.
If a static collection holds references to objects that are no longer needed, they will never be garbage collected.
3. Unclosed Resources
If we don’t close:
Database connections
File streams
Network sockets
Example:
If cache size is not limited, it can grow indefinitely and cause memory issues.
5. Listener or Callback References
If listeners are registered but never removed, they keep objects alive in memory.
Important Point
In short:
Memory leaks in Java occur when unused objects remain referenced, preventing Garbage Collection and
gradually consuming heap memory.
Garbage Collection
Garbage Collection in Java is the automatic process of identifying and removing objects from heap
memory that are no longer reachable, in order to free up memory.
It is handled by the JVM, so the developer does not need to manually deallocate memory like in C or C++.
Yes, we can request Garbage Collection in Java, but we cannot force it.
[Link]();
or
[Link]().gc();
When to run GC
Which algorithm to use
How much memory to reclaim
Forcing GC manually can negatively impact performance because it may trigger unnecessary stop-the-world
pauses.
Best Practice
We should:
Avoid calling [Link]() in production code.
Let JVM manage memory automatically.
Fix memory leaks by removing unnecessary references instead of trying to force GC.
In short:
We can request Garbage Collection using [Link](), but we cannot force it, as the JVM has full control over
when GC actually runs.
Strings
String is immutable in Java, meaning once a String object is created, its value cannot be changed.
There are several important reasons why Java designers made String immutable:
1. Security
Database URLs
File paths
Network connections
Class loading
If String were mutable, its value could be changed after validation, which could lead to security vulnerabilities.
Immutability ensures that once a String is created and validated, it cannot be altered.
Example:
String s1 = "Hello";
String s2 = "Hello";
If Strings were mutable, changing one reference would affect others, breaking the pooling concept.
Immutability allows safe sharing of String objects.
3. Thread Safety
Multiple threads can use the same String object without synchronization.
4. HashCode Caching
If String were mutable and its value changed, the hashcode would change, breaking hash-based collections.
In summary:
Security
Memory optimization (String Pool)
Thread safety
Reliable hashing behavior
That’s why immutability is a critical design decision for the String class.
String Pool is a special memory area inside the Heap where Java stores string literals to optimize
memory usage.
Instead of creating a new object every time, JVM reuses existing String literals from the pool to save memory.
Example
String s1 = "Hello";
String s2 = "Hello";
Here:
So:
s1 == s2 // true
In this case:
So:
s1 == s3 // false
We can use:
[Link]();
String, StringBuilder, and StringBuffer are all used to represent and manipulate character sequences in
Java, but they differ in mutability and thread-safety.
1. String
Immutable
Once created, its value cannot be changed
Stored in String Pool (for literals)
Thread-safe because it is immutable
Example:
String s = "Hello";
s = s + " World";
Use case:
When the value does not need to change frequently.
2. StringBuilder
Mutable
Not thread-safe
Faster than StringBuffer
Introduced in Java 5
Example:
Use case:
When frequent modifications are needed in a single-threaded environment.
3. StringBuffer
Mutable
Thread-safe
Methods are synchronized
Slower than StringBuilder due to synchronization
Example:
Use case:
When multiple threads modify the same string object.
Key Differences
In summary:
Use String when data is constant.
Use StringBuilder for frequent modifications in single-threaded applications.
Use StringBuffer when thread safety is required.
The intern() method is used to move a String object to the String Pool or return the reference of the
existing pooled string if it already exists.
In simple terms, intern() ensures that the string reference points to the String Constant Pool.
Why is it needed?
When we create a String using new, it is stored in the heap, not in the String Pool.
Example:
Using intern()
String s3 = [Link]();
Now:
So:
s3 == s2 // true
Key Points
In summary:
The intern() method ensures that a String object refers to the unique instance stored in the String Pool.
String is commonly used as a key in HashMap because it is immutable, properly implements equals()
and hashCode(), and provides reliable hashing behavior.
1. Immutability
Since String is immutable, its hashCode remains constant, ensuring stable behavior.
This ensures:
Two Strings with the same content are treated as equal keys
Hash-based collections work correctly
Example:
Once computed, it stores the hash value and reuses it, which improves performance in hash-based collections
like HashMap.
In summary:
Immutable
Correctly implements equals() and hashCode()
Efficient due to hashCode caching
List, Set, and Map are core collection interfaces in Java, but they differ in how they store and manage data.
1. List
Common implementations:
ArrayList
LinkedList
Vector
Example:
2. Set
Common implementations:
HashSet → No order
LinkedHashSet → Maintains insertion order
TreeSet → Sorted order
Example:
3. Map
Stores key-value pairs
Keys must be unique
Values can be duplicated
Does not extend Collection interface
Common implementations:
HashMap
LinkedHashMap
TreeMap
Hashtable
Example:
Here:
Key Differences
In summary:
Use List when order and duplicates matter.
Use Set when uniqueness matters.
Use Map when you need key-value mapping.
HashMap stores data in key-value pairs and works internally using a hash table. It uses hashing to
determine where to store each key-value entry in memory.
Step 1: Hashing
A single node, or
A linked list of nodes (if collisions happen), or
A balanced tree (Red-Black Tree) if too many collisions occur (Java 8+).
Step 4: Retrieval
When we call:
[Link]("name");
Time Complexity
Important Points
Not thread-safe
Allows one null key
Allows multiple null values
In summary:
HashMap works by computing the key’s hashCode, mapping it to a bucket index, handling collisions using
linked lists or trees, and using equals() for exact key matching.
Load factor in HashMap defines how full the hash table is allowed to get before it is resized.
It is a measure of how much data can be stored relative to the current capacity.
Default Value
For example:
Default capacity = 16
Load factor = 0.75
Threshold =
16 × 0.75 = 12
So when the 13th element is inserted, the HashMap resizes (capacity becomes 32).
Why 0.75?
After Resizing
Capacity doubles
All existing entries are rehashed
New bucket indexes are recalculated
In summary:
Load factor determines when a HashMap should resize.
It controls the trade-off between memory usage and lookup performance.
A hashCode collision occurs when two different keys produce the same hash value, resulting in the same
bucket index in a HashMap.
HashMap handles collisions using a structured approach.
Before Java 8:
If the size later drops below 6, it may convert back to a linked list.
Important:
hashCode() decides the bucket.
equals() decides the exact key match.
Example
But:
[Link](key2) == false
Performance Impact
In summary:
When hashCode collisions occur, HashMap stores multiple entries in the same bucket using a linked list or a
tree and uses equals() to differentiate between keys
HashMap and ConcurrentHashMap both store key-value pairs, but they differ mainly in thread safety
and internal concurrency handling.
1. Thread Safety
HashMap
Not thread-safe
If multiple threads modify it simultaneously, it may lead to data inconsistency
Requires external synchronization
ConcurrentHashMap
Thread-safe
Designed for concurrent access without locking the entire map
2. Locking Mechanism
HashMap
No internal synchronization
ConcurrentHashMap
HashMap
ConcurrentHashMap
4. Performance
5. Iteration Behavior
HashMap
ConcurrentHashMap
In summary:
Use HashMap in single-threaded scenarios.
Use ConcurrentHashMap in multi-threaded environments where high concurrency is required without
full synchronization.
ArrayList and LinkedList are both implementations of the List interface, but they differ in their internal
data structure and performance characteristics.
ArrayList
LinkedList
2. Access Time
ArrayList
LinkedList
ArrayList
4. Memory Usage
ArrayList
LinkedList
5. Use Case
In summary:
Fail-fast and fail-safe iterators define how a collection behaves when it is modified while being iterated.
Fail-Fast Iterator
Adding
Removing
Updating structure (not just changing value)
Example:
Iterator<String> it = [Link]();
[Link]("B"); // structural modification
Collections like:
ArrayList
HashMap
HashSet
Important:
Fail-fast does not guarantee exception, but it detects modification on best-effort basis.
Fail-Safe Iterator
Fail-safe iterator does not throw exception if the collection is modified during iteration.
Instead:
Example:
ConcurrentHashMap
CopyOnWriteArrayList
Fail-Fast:
Throws ConcurrentModificationException
Works on original collection
Used in non-concurrent collections
Fail-Safe:
No exception
Works on cloned or snapshot copy
Used in concurrent collections
In summary:
Fail-fast iterator fails immediately if collection is modified during iteration, whereas fail-safe iterator operates
on a copy and allows modification without throwing exception.
We must override equals() and hashCode() together to maintain the general contract defined in the
Java Object class, especially when using hash-based collections like HashMap or HashSet.
Example
class Student {
int id;
@Override
public boolean equals(Object o) {
Student s = (Student) o;
return [Link] == [Link];
}
}
Correct Implementation
If equals() is overridden, hashCode() must also be overridden using the same fields used in equals
comparison.
In summary:
We override both equals() and hashCode() together to ensure consistent behavior in hash-based collections
and to satisfy the Java contract that equal objects must have equal hash codes.
Exception Handling
Checked and Unchecked exceptions are two categories of exceptions in Java based on when they are
checked by the compiler.
1. Checked Exceptions
Examples:
IOException
SQLException
ClassNotFoundException
Example:
Checked exceptions usually represent recoverable conditions like file not found or database issues.
2. Unchecked Exceptions
Examples:
NullPointerException
ArithmeticException
ArrayIndexOutOfBoundsException
IllegalArgumentException
Example:
Key Differences
Checked Exception:
Unchecked Exception:
Occur at runtime
Not mandatory to handle
Represent programming mistakes
In summary:
Checked exceptions are compile-time enforced and must be handled, while unchecked exceptions occur at
runtime and are not required to be explicitly handled.
Try-with-resources is a feature introduced in Java 7 that automatically closes resources after execution,
eliminating the need for explicit finally blocks.
File streams
Database connections
BufferedReader
Scanner
Syntax
try (FileReader fr = new FileReader("[Link]")) {
// use the resource
} catch (IOException e) {
[Link]();
}
No need for:
finally {
[Link]();
}
Why It Is Important
Before Java 7:
Try-with-resources:
Multiple Resources
In summary:
Try-with-resources automatically manages and closes resources that implement AutoCloseable, improving code
safety and preventing resource leaks.
The finally block is a part of exception handling in Java that is always executed after the try and catch
blocks, regardless of whether an exception occurs or not.
Purpose of finally
Close resources
Release database connections
Close file streams
Perform cleanup operations
Example
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
[Link]("Exception occurred");
} finally {
[Link]("Finally block executed");
}
Even though an exception occurs, the finally block will still execute.
Important Points
Modern Alternative
For resource management, try-with-resources is preferred over finally because it handles resource closing
automatically.
In summary:
The finally block is used to execute cleanup code that must run regardless of whether an exception occurs or
not.
A custom exception in Java is created by extending either Exception (for checked exceptions) or
RuntimeException (for unchecked exceptions).
In summary:
To create a custom exception, extend Exception or RuntimeException, define constructors, and throw it using
the throw keyword when required.
That means the exception from the finally block will propagate, and the original exception will be lost (unless
handled properly).
Example
try {
int x = 10 / 0; // ArithmeticException
} finally {
throw new RuntimeException("Exception in finally");
}
In this case:
In try-with-resources:
[Link]();
Best Practice
In summary:
If an exception occurs in finally, it overrides any previous exception and becomes the one that propagates,
which can hide the original error.
The thread lifecycle in Java defines the different states a thread goes through from creation to
termination.
1. New
Example:
2. Runnable
[Link]();
3. Running
When the thread scheduler selects the thread, it enters the Running state.
The run() method is being executed.
Note:
Java does not explicitly distinguish Runnable and Running in [Link], but conceptually they are
different.
Blocked
Waiting
Timed Waiting
5. Terminated (Dead)
In summary:
These states represent how a thread moves from creation to completion during execution.
Runnable and Callable are both interfaces used to create tasks that can be executed by a thread, but they
differ in return type and exception handling.
1. Runnable
Used with:
Thread class
ExecutorService
2. Callable
ExecutorService
Returns result via Future
Example:
Key Differences
Runnable:
run() method
No return value
Cannot throw checked exception
Callable:
call() method
Returns a value
Can throw checked exception
In summary:
Race conditions
Data inconsistency
Thread interference
When multiple threads modify shared data simultaneously, the result may become inconsistent.
Example:
class Counter {
int count = 0;
void increment() {
count++;
}
}
If two threads call increment() at the same time, the final value may be incorrect due to race conditions.
Java uses an intrinsic lock (monitor lock) associated with every object.
Synchronized Method
synchronized void increment() {
count++;
}
Synchronized Block
void increment() {
synchronized (this) {
count++;
}
}
synchronized (lockObject) {
// critical section
}
Key Points
In summary:
Synchronization is a mechanism that ensures only one thread accesses shared resources at a time to maintain
data consistency in multi-threaded applications.
volatile is a keyword in Java used to ensure visibility of a variable across multiple threads.
It guarantees that:
Changes made by one thread to a variable
Are immediately visible to other threads
In a multi-threaded environment:
If one thread updates a variable, other threads may still see the old cached value.
Example
class Shared {
volatile boolean flag = false;
}
flag = true;
1. Visibility
2. Prevents instruction reordering (provides memory ordering guarantees)
Example:
synchronized
AtomicInteger
In summary:
volatile ensures visibility of shared variables across threads but does not guarantee atomicity or mutual
exclusion.
Deadlock is a situation in multi-threading where two or more threads are permanently blocked because
each thread is waiting for a resource held by another thread.
Classic Example
class A {}
class B {}
A a = new A();
B b = new B();
Here:
In summary:
Deadlock is a situation where two or more threads are stuck waiting for each other’s resources indefinitely,
preventing program execution from progressing.
A race condition occurs when two or more threads access and modify shared data concurrently, and the
final outcome depends on the timing or order of execution of those threads.
void increment() {
count++;
}
}
1. Read count
2. Increment value
3. Write back
If both threads read the same value before writing, one update may overwrite the other.
Expected result: 2
Actual result may be: 1
Why It Happens
In summary:
A race condition occurs when multiple threads modify shared data without proper synchronization, causing
unpredictable and incorrect results.
43. What is ExecutorService?
ExecutorService is a high-level concurrency framework in Java used to manage and control a pool of
threads for executing tasks asynchronously.
It is part of the [Link] package and provides a better alternative to manually creating and
managing threads.
new Thread().start();
How It Works
[Link](() -> {
[Link]("Task executed");
});
The thread pool executes the task using one of its worker threads.
Common Methods
FixedThreadPool
CachedThreadPool
SingleThreadExecutor
ScheduledThreadPool
Benefits
In summary:
ExecutorService is a thread pool framework that manages and executes asynchronous tasks efficiently without
manually handling threads.
A Thread Pool is a collection of pre-created worker threads that are reused to execute multiple tasks,
instead of creating a new thread for every task.
[Link](() -> {
[Link]("Task executed by " + [Link]().getName());
});
Benefits
In summary:
A Thread Pool is a group of reusable threads used to execute multiple tasks efficiently, improving performance
and controlling concurrency.
Both synchronized and Lock are used to achieve thread synchronization in Java, but they differ in
flexibility and control.
1. Basic Nature
synchronized
Keyword in Java
Built-in language-level feature
Automatically acquires and releases lock
Lock
synchronized
synchronized (this) {
// critical section
}
Lock
[Link]();
try {
// critical section
} finally {
[Link]();
}
3. Flexibility
synchronized
No timeout
No non-blocking attempt
No interruptible lock acquisition
Lock
Provides advanced features:
tryLock() → non-blocking
tryLock(timeout) → wait with timeout
lockInterruptibly() → interruptible lock
Fair locking option
4. Performance
5. Condition Variables
In summary:
It can have:
Example
@FunctionalInterface
interface MyInterface {
void display();
}
Also:
Runnable
Callable
Comparator
In summary:
A functional interface is an interface with exactly one abstract method, used primarily to support lambda
expressions and functional programming in Java.
A lambda expression in Java is a concise way to represent an anonymous function that can be passed as
an argument to a method or stored as a variable.
Key Points
In summary:
A lambda expression is a short, anonymous implementation of a functional interface method, used to write
cleaner and more expressive code in Java.
Stream API is a feature introduced in Java 8 that allows us to process collections of data in a functional
and declarative way.
[Link]()
.filter(num -> num > 10)
.forEach([Link]::println);
It makes code:
More readable
More concise
Easier to parallelize
Stream Pipeline
1. Source
o Collection, array, etc.
2. Intermediate Operations
o filter()
o map()
o sorted()
o distinct()
o These are lazy (not executed immediately)
3. Terminal Operation
o forEach()
o collect()
o count()
o reduce()
o This triggers execution
Example
List<String> names = [Link]("Anjali", "Rahul", "Arun");
Key Features
In summary:
Stream API provides a functional and efficient way to process collections using operations like filter, map, and
reduce, with support for parallel execution.
Both map() and flatMap() are intermediate operations in the Stream API used to transform elements,
but they differ in how they handle nested structures.
map()
Example:
[Link]()
.map(String::toUpperCase)
.forEach([Link]::println);
If input is:
["Anjali", "Rahul"]
Output becomes:
["ANJALI", "RAHUL"]
Each element maps to exactly one element.
flatMap()
Example:
[Link]()
.flatMap(innerList -> [Link]())
.forEach([Link]::println);
Stream<Stream<String>>
A, B, C, D
Key Difference
In summary:
Use map() when each element transforms into a single value.
Use flatMap() when each element produces multiple values and you want a flattened result.
It is used to avoid NullPointerException and to represent the absence of a value in a more expressive way.
Before Java 8:
With Optional:
Common Methods
Example:
Fields
Method parameters
Serialization
In summary:
Optional is a wrapper class that represents the presence or absence of a value, helping to avoid
NullPointerException and making null handling more expressive.
A method reference in Java is a shorthand syntax for referring to an existing method without executing
it.
It is used in place of a lambda expression when the lambda simply calls an existing method.
Method reference was introduced in Java 8 and works with functional interfaces.
It makes code:
More readable
More concise
Cleaner than lambda expressions
Syntax
ClassName::methodName
Equivalent lambda:
4. Reference to a constructor
Equivalent lambda:
In summary:
A method reference is a compact way to refer to an existing method or constructor, used with functional
interfaces to improve readability and reduce boilerplate code.
ACID properties define the four fundamental principles that ensure reliable and consistent database
transactions.
Atomicity
Consistency
Isolation
Durability
1. Atomicity
Atomicity means a transaction must either complete fully or not execute at all.
If any part of the transaction fails, the entire transaction is rolled back.
Example:
If money is transferred from Account A to Account B:
Deduct from A
Add to B
2. Consistency
Consistency means a transaction must bring the database from one valid state to another valid state.
3. Isolation
Isolation means multiple transactions executing concurrently should not interfere with each other.
Read Uncommitted
Read Committed
Repeatable Read
Serializable
Dirty reads
Non-repeatable reads
Phantom reads
4. Durability
Durability means once a transaction is committed, the changes are permanently stored, even if the system
crashes.
In summary:
ACID properties ensure that database transactions are reliable, consistent, isolated from each other, and
permanently stored after commit.
Normalization is the process of organizing data in a database to reduce redundancy and improve data
integrity.
It involves dividing large tables into smaller related tables and defining relationships between them.
Insertion anomaly
Update anomaly
Deletion anomaly
Example:
If student and course details are stored in one table, repeating student data for every course leads to redundancy.
Normal Forms
No repeating groups
Each column contains atomic (indivisible) values
Each row is unique
Example:
No multiple phone numbers in one column.
Must be in 1NF
No partial dependency
All non-key attributes must depend on the entire primary key
Must be in 2NF
No transitive dependency
Non-key attributes should depend only on the primary key
Example:
If Student table stores department name and department location, and location depends on department, not
student → transitive dependency → must separate.
Benefits
Reduces redundancy
Improves data integrity
Makes database more maintainable
Trade-off
Highly normalized databases may require more joins, which can impact performance.
In summary:
Normalization is the process of structuring database tables to eliminate redundancy and ensure data integrity by
following normal forms like 1NF, 2NF, and 3NF.
Convert to 1NF
1 Anjali 9876
1 Anjali 8765
It is already in 1NF
No partial dependency exists
Example
Here:
Fix
Split into:
Student Table
| StudentID | StudentName |
Enrollment Table
| StudentID | CourseID |
It is in 2NF
No transitive dependency exists
Example
If:
DepartmentName depends on DepartmentID
Not directly on StudentID
Fix
Student Table
| StudentID | DepartmentID |
Department Table
| DepartmentID | DepartmentName |
Simple Way to Remember
In summary:
1NF ensures atomic values,
2NF removes partial dependency,
3NF removes transitive dependency to reduce redundancy and maintain data integrity.
Indexing is a database optimization technique used to improve the speed of data retrieval operations on a
table.
It works similarly to an index in a book — instead of scanning the entire table, the database uses the index to
quickly locate the required rows.
Without an index:
With an index:
If email is indexed:
Types of Indexes
Trade-offs
Advantages:
Disadvantages:
In summary:
Indexing improves query performance by creating a data structure (usually B-Tree) that allows fast lookup of
rows, but it increases storage and write operation cost.
Database scaling is the process of increasing a database system’s capacity and performance to handle
growing data volume and traffic.
For example:
Advantages:
Simple to implement
No changes in application logic
Disadvantages:
Hardware limits
Single point of failure
Expensive at higher levels
Horizontal scaling means adding more database servers and distributing the load.
This includes:
a) Read Replicas
b) Sharding
Example:
Advantages:
Highly scalable
Handles very large traffic
Disadvantages:
Complex implementation
Requires data distribution logic
In summary:
Database scaling is the process of improving database capacity and performance either by increasing server
resources (vertical scaling) or by distributing data across multiple servers (horizontal scaling).
Sharding is a database scaling technique where a large database is split into smaller, independent
databases called shards, each storing a portion of the data.
Example:
Each shard:
1. Range-based sharding
Data split by value ranges
2. Hash-based sharding
Use hash function on shard key
3. shard = hash(userId) % number_of_shards
4. Geographic sharding
Based on region (e.g., India, US, Europe)
Advantages
Challenges
Complex to implement
Cross-shard joins are difficult
Rebalancing data is hard
Requires shard key design carefully
In summary:
Sharding is a horizontal scaling technique where data is partitioned across multiple databases to improve
scalability and handle large volumes of traffic.
57. What is transaction isolation level?
Transaction isolation level defines how much one transaction is isolated from other concurrent
transactions in a database system.
It controls how and when changes made by one transaction become visible to others.
When multiple transactions run at the same time, problems can occur such as:
Dirty reads
Non-repeatable reads
Phantom reads
1. Read Uncommitted
Example:
Transaction A updates data but does not commit.
Transaction B reads that uncommitted value.
2. Read Committed
Rows read cannot be changed by other transactions until current transaction completes.
Prevents dirty reads and non-repeatable reads.
Phantom reads may still occur (depending on DB).
4. Serializable
In summary:
Transaction isolation level determines how visible one transaction’s changes are to others and helps control
concurrency issues in database systems.
Optimistic locking and pessimistic locking are two concurrency control mechanisms used to handle
concurrent updates in a database.
1. Pessimistic Locking
Pessimistic locking assumes that conflicts are likely to happen, so it locks the data immediately when it is
read.
Other transactions cannot modify the locked data until the lock is released.
Example:
SELECT * FROM users WHERE id = 1 FOR UPDATE;
Characteristics:
Use Case:
When:
2. Optimistic Locking
Optimistic locking assumes that conflicts are rare, so it does not lock the row when reading.
Version column
Timestamp
Example:
id name version
1 Anjali 1
Update query:
UPDATE users
SET name = 'A', version = version + 1
WHERE id = 1 AND version = 1;
Characteristics:
When:
Key Differences
Pessimistic Locking:
Optimistic Locking:
In summary:
Pessimistic locking prevents conflicts by locking data early, while optimistic locking allows concurrent access
and detects conflicts at the time of update.
Spring Boot is a framework built on top of the Spring Framework that simplifies the development of
production-ready, stand-alone Java applications with minimal configuration.
It reduces boilerplate configuration and helps developers quickly build REST APIs, microservices, and web
applications.
Auto-configuration
Embedded server
Starter dependencies
Key Features
1. Auto-Configuration
Automatically configures application based on dependencies present in classpath.
2. Starter Dependencies
Predefined dependency groups like:
o spring-boot-starter-web
o spring-boot-starter-data-jpa
o spring-boot-starter-security
3. Embedded Server
Comes with embedded Tomcat (default), Jetty, or Undertow.
No need to deploy WAR separately.
4. Production-Ready Features
o Actuator (health checks, metrics)
o Externalized configuration
o Logging support
Example
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}
@Configuration
@EnableAutoConfiguration
@ComponentScan
In summary:
Spring Boot is a convention-over-configuration framework that simplifies building and deploying Spring-based
applications by providing auto-configuration, embedded servers, and starter dependencies.
60. What is Dependency Injection?
Dependency Injection (DI) is a design pattern where the dependencies of a class are provided from the
outside instead of the class creating them itself.
Here:
Car(Engine engine) {
[Link] = engine;
}
}
Now:
Example:
@Service
class CarService {
Benefits
Loose coupling
Easier testing (mock dependencies)
Better maintainability
Follows SOLID principles
In summary:
Dependency Injection is a design pattern where objects receive their dependencies from an external source
rather than creating them internally, enabling loose coupling and better software design.
IoC container (Inversion of Control container) is a core part of the Spring framework that is responsible
for creating, managing, and injecting dependencies between objects (beans).
In IoC:
The control of object creation and dependency management is transferred to the container.
The container manages the lifecycle of objects.
1. BeanFactory
o Basic container
o Lazy initialization
2. ApplicationContext
o Advanced container
o Supports:
AOP
Internationalization
Event propagation
Eager initialization
Example
@Service
class Engine {}
@Service
class Car {
Here:
In summary:
The IoC container is a Spring component that manages object creation, dependency injection, and lifecycle
management, implementing the principle of Inversion of Control.
It tells the Spring IoC container to automatically resolve and inject a required bean into a class.
How It Works
@Service
class Car {
@Autowired
public Car(Engine engine) {
[Link] = engine;
}
}
Note:
In modern Spring versions, if a class has only one constructor, @Autowired is optional.
Other Injection Types
1. Field Injection
@Autowired
private Engine engine;
Hard to test
Breaks immutability
2. Setter Injection
@Autowired
public void setEngine(Engine engine) {
[Link] = engine;
}
@Qualifier
@Primary
In summary:
@Autowired is used in Spring to automatically inject required dependencies by type from the IoC container into
a class.
@Component, @Service, and @Repository are Spring stereotype annotations used to declare beans, but
they serve different semantic purposes in application architecture.
All three are detected during component scanning and registered as Spring beans.
1. @Component
@Component
class UtilityClass {
}
Use when:
2. @Service
Example:
@Service
class UserService {
}
3. @Repository
Example:
@Repository
class UserRepository {
}
Extra feature:
Key Differences
@Component
Generic bean
@Service
@Repository
In summary:
All three create Spring-managed beans, but @Service is used for business logic, @Repository for database
operations, and @Component for general-purpose components.
The Spring Bean lifecycle describes the stages a bean goes through from creation to destruction inside the
Spring IoC container.
1. Bean Instantiation
Constructor
Or factory method
At this stage, the object is created but dependencies are not injected yet.
2. Dependency Injection
Constructor injection
Setter injection
Field injection
3. Aware Interfaces (Optional)
BeanNameAware
BeanFactoryAware
ApplicationContextAware
4. Pre-Initialization
Spring calls:
@PostConstruct method
afterPropertiesSet() (if implementing InitializingBean)
Custom init-method (if defined)
6. Pre-Destruction
7. Bean Destruction
Simple Flow
In summary:
The Spring Bean lifecycle includes creation, dependency injection, initialization, usage, and destruction, all
managed by the Spring IoC container.
REST API (Representational State Transfer API) is an architectural style used to design scalable and
stateless web services that communicate over HTTP.
1. Stateless
o Each request from client contains all necessary information.
o Server does not store client session state.
2. Client-Server Architecture
o Clear separation between client and server.
3. Resource-Based
o Everything is treated as a resource.
o Each resource is identified by a URI.
Example:
/users
/users/1
/orders/100
Example:
GET /users/1
POST /users
DELETE /users/1
Data Format
{
"id": 1,
"name": "Anjali"
}
REST is lightweight
Uses HTTP directly
No strict protocol like SOAP
Easier to scale
In summary:
REST API is a stateless, resource-based web service architecture that uses HTTP methods to perform CRUD
operations and typically communicates using JSON.
@RestController is a Spring annotation used to create RESTful web services. It combines @Controller
and @ResponseBody.
@Controller
@ResponseBody
So every method inside the class automatically returns data, not a view.
Example
@RestController
@RequestMapping("/users")
class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable int id) {
return "User ID: " + id;
}
}
When we call:
GET /users/1
User ID: 1
@RestController
In summary:
@RestController is a Spring annotation used to build REST APIs, where methods return response data
directly instead of view pages.
@RequestMapping is a Spring annotation used to map HTTP requests to specific handler methods or
classes.
It defines:
URL path
HTTP method
Request parameters
Headers
Content type
Basic Usage
At class level:
@RestController
@RequestMapping("/users")
class UserController {
}
At method level:
This maps:
GET /users/{id}
to this method.
Instead of writing:
@RequestMapping(method = [Link])
We can use:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
Example:
@GetMapping("/{id}")
In summary:
@RequestMapping is used in Spring to map HTTP requests to controller methods by specifying URL patterns
and HTTP methods.
JWT (JSON Web Token) is a compact, URL-safe token format used for securely transmitting
information between parties, commonly used for authentication and authorization in REST APIs.
Structure of JWT
[Link]
Example:
[Link]
1. Header
Contains:
Example:
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload
Example:
{
"sub": "12345",
"role": "ADMIN",
"exp": 1700000000
}
3. Signature
Created by:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secretKey
)
Important Points
In summary:
JWT is a stateless authentication token consisting of header, payload, and signature, used to securely transmit
user identity and authorization information in web applications.
Spring Security is a powerful and customizable authentication and authorization framework for securing
Java and Spring-based applications.
Authentication
Authorization
Protection against common attacks
1. Authentication vs Authorization
Authentication
→ Verifying who the user is
Example: Username and password validation
Authorization
→ Verifying what the user is allowed to access
Example: Only ADMIN can access /admin endpoint
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin();
return [Link]();
}
}
5. Why It Is Important
In summary:
Spring Security is a comprehensive security framework that provides authentication, authorization, and
protection against common web security threats in Spring applications.
CORS (Cross-Origin Resource Sharing) is a security mechanism implemented by browsers that controls
how resources on a web server can be requested from a different origin.
Protocol (http/https)
Domain
Port
Example:
Frontend: [Link]
Backend: [Link]
This means:
A web page can only make requests to the same origin by default.
Origin: [Link]
Access-Control-Allow-Origin: [Link]
Preflight Request
Allowed methods
Allowed headers
Example:
@CrossOrigin(origins = "[Link]
@RestController
class UserController {
}
Important Point
CORS is a browser security mechanism that controls cross-origin HTTP requests and allows servers to specify
which external origins can access their resources.
Hibernate is an Object-Relational Mapping (ORM) framework for Java that simplifies database
interaction by mapping Java objects to database tables.
Hibernate automates:
Object-table mapping
SQL generation
Connection handling
Caching
Hibernate maps:
Example:
@Entity
class User {
@Id
private Long id;
Key Features
Hibernate vs JPA
In summary:
Hibernate is a Java ORM framework that maps Java objects to database tables and simplifies database
operations by automatically handling SQL generation and object mapping.
JPA (Java Persistence API) is a specification in Java that defines how Java objects should be mapped to
relational database tables.
It is not a framework itself, but a standard set of interfaces and annotations for ORM (Object-Relational
Mapping).
Why JPA Is Needed
Before JPA:
JPA provides:
A common standard
Portable persistence logic
Vendor independence
Important Point
Hibernate
EclipseLink
OpenJPA
1. Entity
@Entity
class User {
@Id
private Long id;
2. EntityManager
Persist
Remove
Find
Merge
3. Persistence Context
Key Features
JPA vs Hibernate
JPA → Specification
Hibernate → Implementation of JPA
In summary:
JPA is a Java specification that defines standard ORM mapping and persistence operations, while frameworks
like Hibernate implement it to provide actual functionality.
Lazy loading and Eager loading define when related entities are fetched from the database in ORM
frameworks like JPA or Hibernate.
1. Eager Loading
Related entities are fetched immediately along with the main entity.
Data is loaded in the same query or immediately after.
Example:
@OneToMany(fetch = [Link])
private List<Order> orders;
If we fetch a User:
Pros:
No LazyInitializationException
Data is ready to use
Cons:
2. Lazy Loading
Example:
@OneToMany(fetch = [Link])
private List<Order> orders;
Only when:
[Link]();
Pros:
Better performance
Loads only required data
Cons:
In summary:
Eager loading fetches related data immediately, while lazy loading fetches related data only when accessed,
providing better performance but requiring careful transaction management.
The N+1 problem is a performance issue in ORM frameworks like Hibernate where one query is
executed to fetch parent entities, and then an additional query is executed for each parent to fetch related
entities.
This results in N+1 queries instead of just 1 or 2, which severely impacts performance.
Example
Suppose we have:
User
Order (OneToMany relationship)
This executes:
So total queries =
Why It Happens
Lazy loading
Iterating over collections
Improper fetching strategy
Why It Is Bad
How To Fix It
2. Use @EntityGraph
3. Use batch fetching
In summary:
The N+1 problem occurs when fetching one set of entities results in additional queries for each related entity,
causing performance degradation due to excessive database calls.
Why It Is Needed
Example
@Service
class UserService {
@Transactional
public void transferMoney(Account from, Account to, double amount) {
[Link](amount);
[Link](amount);
}
}
If credit() fails:
Spring uses:
We can customize:
@Transactional(rollbackFor = [Link])
Important Points
In summary:
@Transactional is a Spring annotation that defines transaction boundaries, ensuring that a group of database
operations either fully commit or fully roll back based on execution outcome.
76. What happens internally when a REST request hits Spring Boot?
When a REST request hits a Spring Boot application, it goes through a structured processing flow inside
the Spring MVC framework before generating a response.
It:
3. Handler Mapping
Example:
GET /users/1
Mapped to:
@GetMapping("/users/{id}")
4. Handler Adapter
5. Controller Execution
It may:
If using @RestController:
In summary:
When a REST request hits Spring Boot, it flows through the embedded server, DispatcherServlet, handler
mapping, controller execution, message conversion, and finally returns a JSON response to the client.
SOLID is a set of five object-oriented design principles that help in writing clean, maintainable, scalable,
and loosely coupled code.
❌ Bad:
class UserService {
void saveUser() {}
void sendEmail() {}
void generateReport() {}
}
✔ Good:
Software entities should be open for extension but closed for modification.
Example:
Use interfaces and polymorphism instead of if-else blocks.
Subclasses should be replaceable with their parent class without breaking functionality.
interface Worker {
void work();
void eat();
}
Instead of:
class Car {
Engine engine = new DieselEngine();
}
Use:
class Car {
Engine engine;
}
In summary:
SOLID principles promote good object-oriented design by encouraging single responsibility, extensibility,
substitutability, interface clarity, and dependency on abstractions rather than concrete implementations.
Each microservice:
Why Microservices?
User Service
Order Service
Payment Service
Inventory Service
Each service:
Runs independently
Can scale independently
Can be developed by different teams
Key Characteristics
Independent deployment
Decentralized database
Lightweight communication (REST, Kafka, etc.)
Fault isolation
Technology independence
REST APIs
Message queues (Kafka, RabbitMQ)
Service discovery
Advantages
Better scalability
Faster development
Fault isolation
Easier maintenance
Challenges
In summary:
Microservices is an architectural approach where an application is divided into small, independent services that
communicate over a network and can be developed, deployed, and scaled independently.
Monolithic architecture is a traditional software design approach where the entire application is built as
a single, unified codebase and deployed as one unit.
Typically includes:
UI layer
Business logic layer
Data access layer
Database
All packaged and deployed together as a single application (e.g., one WAR/JAR file).
Example
In an e-commerce application:
User module
Order module
Payment module
Inventory module
Advantages
Disadvantages
Monolithic:
Microservices:
In summary:
Monolithic architecture is a design where all components of an application are tightly integrated and deployed
as a single unit, making it simpler initially but harder to scale and maintain as the system grows.
An API Gateway is a single entry point for all client requests in a microservices architecture.
Instead of clients calling multiple microservices directly, they send requests to the API Gateway, which routes
them to the appropriate service.
In microservices:
If we have:
User Service
Order Service
Payment Service
1. Request routing
2. Authentication & authorization
3. Rate limiting
4. Logging & monitoring
5. Load balancing
6. Aggregating responses from multiple services
Example
Client request:
GET /api/orders/1
API Gateway:
Benefits
In summary:
An API Gateway is a centralized entry point in microservices architecture that routes client requests to
appropriate services and handles cross-cutting concerns like security, logging, and load balancing.
A Circuit Breaker is a design pattern used in microservices to prevent a system from repeatedly trying to
call a failing service.
Why It Is Needed
In microservices:
3. Half-Open
Example
Instead of:
Circuit Breaker:
Stops calling it
Returns fallback response like:
“Payment service temporarily unavailable”
Benefits
Common Tools
Resilience4j
Netflix Hystrix (deprecated)
In summary:
A Circuit Breaker is a fault-tolerance pattern that stops repeated calls to a failing service, protecting the system
from cascading failures and improving resilience in microservices architecture.
Caching is a technique used to store frequently accessed data in a temporary storage layer so that future
requests can be served faster without repeatedly querying the database or external service.
Without caching:
With caching:
Example
Suppose we have:
GET /products/1
No DB call needed.
Types of Caching
1. In-Memory Cache
2. Distributed Cache
Caching Strategies
Benefits
Improved performance
Reduced database load
Better scalability
Lower latency
Challenges
In summary:
Caching is a performance optimization technique where frequently accessed data is stored temporarily to reduce
database load and improve response time.
Load balancing is the process of distributing incoming network traffic across multiple servers to ensure
no single server becomes overloaded.
It improves:
Performance
Scalability
High availability
Example
Server A
Server B
Server C
1. Round Robin
Requests are distributed sequentially.
2. Least Connections
Sends request to server with least active connections.
3. IP Hash
Same client IP goes to same server.
4. Weighted Round Robin
Servers with higher capacity receive more traffic.
Physical device.
Examples:
NGINX
HAProxy
AWS ELB
Benefits
Improved performance
High availability
Fault tolerance
Horizontal scalability
In summary:
Load balancing distributes incoming requests across multiple servers to improve performance, availability, and
scalability of an application.
Vertical scaling and horizontal scaling are two approaches to increase the capacity and performance of a
system.
1. Vertical Scaling (Scaling Up)
For example:
Advantages:
Simple to implement
No major architecture change
Easy to manage
Disadvantages:
Example:
If your database is slow → upgrade the server hardware.
Horizontal scaling means adding more servers and distributing the load.
Example:
Server A
Server B
Server C
Advantages:
Highly scalable
Fault tolerant
Better for large systems
Disadvantages:
More complex
Requires load balancing
Data consistency challenges
Quick Comparison
Vertical:
Horizontal:
In summary:
Vertical scaling increases the capacity of a single server, while horizontal scaling increases system capacity by
adding multiple servers and distributing the load.
Docker is a containerization platform that allows applications to be packaged along with their
dependencies into lightweight, portable containers.
Without Docker:
With Docker:
What Is a Container?
A container:
1. Docker Image
o Blueprint of application
o Read-only template
2. Docker Container
o Running instance of image
3. Dockerfile
o Script to create image
Example:
FROM openjdk:17
COPY [Link] [Link]
ENTRYPOINT ["java", "-jar", "[Link]"]
How It Works
1. Build image
2. Run container
3. Application runs in isolated environment
Benefits
Portability
Lightweight
Faster deployment
Environment consistency
Easy scaling
Docker vs Virtual Machine
Docker:
Shares OS kernel
Lightweight
Fast startup
VM:
Full OS
Heavy
Slower startup
In summary:
Docker is a containerization platform that packages applications and their dependencies into lightweight,
portable containers to ensure consistent execution across environments.
CI/CD stands for Continuous Integration and Continuous Deployment (or Continuous Delivery). It is a
DevOps practice that automates the process of building, testing, and deploying applications.
Benefits:
Example flow:
Developer pushes code →
Jenkins/GitHub Actions runs build →
Tests execute automatically.
3. Continuous Deployment
1. Code commit
2. Build
3. Run tests
4. Package (e.g., Docker image)
5. Deploy to staging/production
Jenkins
GitHub Actions
GitLab CI
CircleCI
Azure DevOps
In summary:
CI/CD is an automated software development practice where code changes are continuously integrated, tested,
and deployed to ensure faster, reliable, and consistent application delivery.
Encryption
Domain: Security
Definition (interview-ready):
Encryption is the process of converting readable data (plaintext) into unreadable data (ciphertext) using an
algorithm and a key, so that only authorized parties can decrypt it.
Key Points:
Uses a key
Reversible (with correct key)
Used for secure communication
Example: HTTPS, SSL/TLS
Flow:
Plaintext → Encrypt (with key) → Ciphertext
Ciphertext → Decrypt (with key) → Plaintext
Purpose:
Confidentiality
Encoding
Definition:
Encoding is the process of converting data into another format so it can be safely transmitted or stored, but it is
NOT meant for security.
Key Points:
No secret key involved
Easily reversible
Used for data formatting
Example: Base64, UTF-8
Example:
Binary data → Base64 string
Used when sending images in JSON.
Purpose:
Data compatibility, not security.
Hashing
Definition:
Hashing is a one-way process that converts data into a fixed-length hash value using a hash function.
Key Points:
Example:
Password → SHA-256 → Random-looking string
Purpose:
Integrity + Secure storage
HTTP status codes are standardized 3-digit response codes returned by a server to indicate the result of a
client’s HTTP request.
1xx → Informational
2xx → Success
3xx → Redirection
4xx → Client Error
5xx → Server Error
200 OK
201 Created
202 Accepted
204 No Content
302 Found
401 Unauthorized
403 Forbidden
409 Conflict
Request body format not supported (e.g., sending XML when JSON expected).
Quick Summary
2xx → Success
3xx → Redirection
4xx → Client mistakes
5xx → Server issues
In summary:
HTTP status codes communicate the result of an HTTP request, indicating whether it was successful, redirected,
failed due to client error, or failed due to server error.
1. What is React?
eact is a JavaScript library used for building user interfaces, especially single-page applications (SPAs).
It was developed by Facebook and is primarily used to build dynamic, fast, and interactive web applications.
Component-based architecture
Virtual DOM
Unidirectional data flow
1. Component-Based Architecture
Navigation bar
Sidebar
ProductCard
Footer
Each component:
2. Virtual DOM
Parent → Child
Example
function Welcome() {
return <h1>Hello, Anjali</h1>;
}
Reusable components
Fast rendering (Virtual DOM)
Large ecosystem
Strong community support
Works well with REST APIs
In summary:
React is a component-based JavaScript library for building fast and interactive user interfaces using Virtual
DOM and unidirectional data flow.
Virtual DOM is a lightweight in-memory representation of the real DOM used by React to optimize UI
updates.
Instead of directly updating the browser’s real DOM, React first updates the Virtual DOM.
Slow
Expensive
Performance-heavy
Reflow
Repaint
Step-by-step process:
Important Note
In summary:
Virtual DOM is a lightweight copy of the real DOM that React uses to efficiently detect changes and update
only the modified parts of the UI, improving performance.
Components in React are independent, reusable pieces of UI that define how a part of the user interface
looks and behaves.
Functional and Class components are two ways to create components in React, but functional
components are now preferred due to simplicity and Hooks support.
1. Functional Components
function Welcome() {
return <h1>Hello</h1>;
}
Manage state
Handle lifecycle logic
Perform side effects
Advantages:
Simpler syntax
Less boilerplate
Easier to read and test
Better performance (in modern React)
2. Class Components
To manage state:
[Link] = { count: 0 };
To handle lifecycle:
componentDidMount()
componentDidUpdate()
componentWillUnmount()
Disadvantages:
More boilerplate
this binding issues
Harder to maintain
Key Differences
Functional:
Uses Hooks
No this keyword
Simpler and modern
Class:
In summary:
Functional components are simpler and use Hooks for state and lifecycle management, while class components
use ES6 classes and traditional lifecycle methods. Modern React applications prefer functional components.
Props (short for properties) are read-only inputs passed from a parent component to a child component
in React.
Parent → Child
Example
Parent Component:
function App() {
return <Welcome name="Anjali" />;
}
Child Component:
function Welcome(props) {
return <h1>Hello, {[Link]}</h1>;
}
Here:
name is a prop.
It is passed from App to Welcome.
Important Characteristics
In summary:
Props are read-only data passed from parent to child components in React, enabling dynamic and reusable UI
components.
6. What is state?
State in React is a built-in object that stores data that can change over time and affects how a component
renders.
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Here:
Props:
State:
In summary:
State is a React component’s internal, mutable data that controls dynamic behavior and causes the component to
re-render when updated.
8. What is useState?
It returns:
Current state value
A function to update the state
Example:
9. What is useEffect?
API calls
Subscriptions
Timers
DOM manipulation
Example:
useEffect(() => {
[Link]("Component mounted");
});
useEffect(() => {
// effect logic
}, [dependency]);
1. No dependency array
→ Runs after every render
2. Empty array []
→ Runs only once (on mount)
3. With dependencies [value]
→ Runs when that value changes
It runs:
Example:
useEffect(() => {
const timer = setInterval(() => {
[Link]("Running");
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
Used to:
Clear timers
Remove event listeners
Cancel subscriptions
useRef is a Hook that stores a mutable value that does not cause re-render when updated.
Used for:
Example:
Custom hooks are reusable functions that use React Hooks internally to share logic between components.
Example:
function useCounter() {
const [count, setCount] = useState(0);
return { count, setCount };
}
Custom hooks:
Quick Summary
8. What is useRef?
9. What is useMemo?
10. What is useCallback?
11. What are custom hooks?
Reconciliation is the process React uses to compare the previous Virtual DOM with the new Virtual
DOM and determine the minimal set of changes needed to update the real DOM.
Example:
{[Link](item => (
<li key={[Link]}>{[Link]}</li>
))}
Important:
Keys must be unique and stable.
Avoid using array index as key if list can change.
React re-renders the component function, but updates real DOM only if needed.
Common techniques:
Memoization is a performance optimization technique where React stores the result of a function and
reuses it if inputs haven’t changed.
Used with:
[Link] is a higher-order component that prevents re-rendering of a component if its props have not
changed.
Example:
Controlled Components
Example:
function Form() {
const [name, setName] = useState("");
return (
<input
value={name}
onChange={(e) => setName([Link])}
/>
);
}
Here:
Advantages:
Uncontrolled Components
In uncontrolled components, form data is handled by the DOM itself.
Example:
function Form() {
const inputRef = useRef();
[Link]
When to use:
Simple forms
Less control required
Key Difference
Example:
function Form() {
const [name, setName] = useState("");
return (
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={(e) => setName([Link])}
/>
<button type="submit">Submit</button>
</form>
);
}
Steps:
1. Attach onSubmit
2. Prevent default behavior
3. Process form data
[Link]();
Quick Summary
State Management
Lifting state up is the process of moving state from a child component to a common parent component so
that multiple child components can share the same data.
Instead of:
We:
Move the state to their closest common parent
Pass data down via props
Example:
function Parent() {
const [value, setValue] = useState("");
return (
<>
<Input value={value} setValue={setValue} />
<Display value={value} />
</>
);
}
Prop drilling is the process of passing props through multiple intermediate components just to reach a
deeply nested child.
Example:
Even if Child and Grandchild don’t use the prop, they must pass it.
Problem:
Solution:
Context API
Redux
Context API is a React feature that allows data to be shared globally without passing props manually at
every level.
Used for:
Theme
Authentication
Language
Global settings
Example:
function App() {
return (
<[Link] value="dark">
<Child />
</[Link]>
);
}
Redux is a predictable state management library used to manage global application state.
Used when:
Large applications
Complex state sharing
Multiple components need same data
Flow steps:
Example:
Reducer:
Quick Summary
Backend Integration
fetch()
axios
useEffect(() => {
fetch("/api/users")
.then(res => [Link]())
.then(data => setUsers(data))
.catch(err => [Link](err));
}, []);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("/api/users");
const data = await [Link]();
setUsers(data);
} catch (error) {
[Link](error);
}
};
fetchData();
}, []);
Best practice: Call APIs from a separate service layer, not directly inside components.
Why?
Example:
[Link]
useEffect(() => {
getUsers().then(setUsers);
}, []);
Example:
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const data = await getUsers();
setUsers(data);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
Render conditionally:
try {
const data = await getUsers();
setUsers(data);
} catch (err) {
setError("Failed to fetch data");
}
Render conditionally:
Toast notifications
Error boundaries
Retry mechanisms
Common options:
localStorage
sessionStorage
HTTP-only cookies
Typical example:
[Link]("token", jwtToken);
localStorage
Pros:
Easy to use
Accessible via JS
Cons:
Pros:
Cons:
Best Practice
If simple app:
Routing
React Router is a library used for handling navigation and routing in React applications.
It enables Single Page Applications (SPAs) to navigate between different views without reloading the entire
page.
Example:
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
BrowserRouter is a router implementation that uses the browser’s HTML5 History API to keep the UI in
sync with the URL.
/dashboard
/profile
/orders
Instead of hash-based URLs like:
/#/dashboard
Example usage:
<BrowserRouter>
<App />
</BrowserRouter>
BrowserRouter:
Protected routes are routes that are accessible only to authenticated users.
Dashboard
Profile
Admin pages
Example:
Usage:
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
Advanced
Lazy loading in React means loading components only when they are needed instead of loading
everything at once.
This improves:
Example:
function App() {
return (
<Suspense fallback={<p>Loading...</p>}>
<Dashboard />
</Suspense>
);
}
Here:
Code splitting is the process of splitting a large JavaScript bundle into smaller chunks that can be loaded
on demand.
By default:
React apps bundle everything into one large JS file.
That slows initial load.
Code splitting:
[Link]
Dynamic import()
Route-based splitting
A Higher-Order Component (HOC) is a function that takes a component and returns a new enhanced
component.
Pattern:
function withLogger(WrappedComponent) {
return function EnhancedComponent(props) {
[Link]("Component rendered");
return <WrappedComponent {...props} />;
};
}
Usage:
Authentication logic
Logging
Authorization
Data fetching
Note:
With Hooks, HOCs are less common now but still important to know.
StrictMode is a development-only tool in React that helps identify potential problems in an application.
It does NOT affect production build.
Usage:
<[Link]>
<App />
</[Link]>
What it does:
Important:
It runs components twice in development to detect side-effect bugs.
Quick Summary
Hi, I’m Anjali. I’m a Computer Science graduate with a strong interest in software development, especially
backend development using Java, SQL, and REST APIs.
I started my career as a Full Stack Developer, and later worked as a System Engineer on a contract role at IISc.
While that role did not involve heavy day-to-day coding, it gave me exposure to production systems, structured
environments, and how large institutions operate.
Throughout that period, I never stepped away from coding. I consistently worked on strengthening my core
computer science fundamentals and built projects on my own, including a full-stack e-commerce application
using Spring Boot, React, and SQL.
Through these projects, I focused on backend concepts like REST API design, database design, transactions,
and clean service-layer logic. I’ve always been genuinely interested in software engineering, and coding has
been a constant part of my journey even when my job role didn’t fully reflect it.
Right now, I’m actively looking for a backend or full-stack role where I can work more closely with code, apply
the skills I’ve built, and continue growing as a software engineer.
E-COMMERCE PROJECT — ONE GO EXPLANATION
One of my main projects is an E-commerce application built using Spring Boot for the backend, React for the
frontend, and a SQL database for data storage.
The goal of this project was to design and build a complete end-to-end system that handles core e-commerce
functionalities such as user management, product management, order processing, and data consistency.
From a functional perspective, the application allows users to register and log in, browse products, add items to
a cart, and place orders.
From a backend perspective, the system is implemented as a REST-based application using Spring Boot,
following a layered architecture with controller, service, and repository layers. Each layer has a clear
responsibility, which helps keep the code modular and maintainable.
I paid particular attention to database design. I designed relational tables for users, products, orders, and order
items, and defined proper relationships using foreign keys to maintain data integrity.
For API design, I followed REST principles and used appropriate HTTP methods and status codes. I
implemented validation at the service layer to handle invalid requests and ensure business rules are enforced
before interacting with the database.
One important aspect I worked on was order processing. When a user places an order, the system creates an
order record along with associated order items, and this is handled within a transactional boundary to ensure
consistency—so either the entire order is saved successfully or nothing is persisted.
On the frontend, I used React to consume the backend APIs and manage application state. The frontend
communicates with the backend through REST APIs.
Through this project, I gained hands-on experience in designing REST APIs, structuring backend applications,
relational database design, and integrating a React frontend with a Spring Boot backend.
SOLID is a set of five design principles that help us write clean, maintainable, scalable, and loosely coupled
object-oriented code.
They help improve readability, flexibility, and make systems easier to extend without breaking existing
functionality.
This principle states that a class should have only one reason to change, meaning it should have only one
responsibility.
For example, in an e-commerce system, instead of having one class handling order processing, payment, and
email notifications, we should separate them into different classes like OrderService, PaymentService, and
NotificationService.
This makes code easier to maintain and test because changes in one functionality don’t affect others.
This principle says that software entities should be open for extension but closed for modification.
That means we should be able to add new functionality without changing existing code.
For example, if we have a Payment interface, we can add new payment methods like UPI or CreditCard by
creating new classes implementing the interface instead of modifying existing logic.
This principle states that a subclass should be able to replace its parent class without affecting program
correctness.
In other words, child classes should behave in a way that doesn’t break expectations of the base class.
A classic example is if a Bird class has a fly() method, then a Penguin subclass should not extend Bird because
penguins cannot fly.
This principle says that clients should not be forced to depend on interfaces they do not use.
Instead of having a large interface with many methods, we should split it into smaller, more specific interfaces.
For example, instead of a single Worker interface with work() and eat(), we can create separate interfaces like
Workable and Eatable so classes only implement what they need.
This improves flexibility and reduces unnecessary dependencies.
This principle states that high-level modules should not depend on low-level modules. Both should depend on
abstractions.
Also, abstractions should not depend on details — details should depend on abstractions.
In Spring Boot, this is achieved using dependency injection. For example, a service depends on a Payment
interface instead of a specific implementation like CreditCardPayment.
In summary, SOLID principles help us build scalable and maintainable software by promoting loose coupling,
high cohesion, and better separation of concerns.
They are widely used in enterprise applications and frameworks like Spring Boot.
“In my project I applied SRP by separating controller, service, and repository layers, and used DIP through
dependency injection.”