0% found this document useful (0 votes)
2 views29 pages

Java SpringBoot Interview Guide

The document is a comprehensive interview preparation guide for Java and Spring Boot, covering key topics such as Stream API, immutability, custom exceptions, the final keyword, collection processing, synchronization, deadlock avoidance, and code optimization. It provides detailed explanations, examples, and best practices for each topic, making it a valuable resource for candidates preparing for technical interviews. The guide emphasizes important concepts and techniques necessary for effective Java programming and application development.

Uploaded by

Vipul
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views29 pages

Java SpringBoot Interview Guide

The document is a comprehensive interview preparation guide for Java and Spring Boot, covering key topics such as Stream API, immutability, custom exceptions, the final keyword, collection processing, synchronization, deadlock avoidance, and code optimization. It provides detailed explanations, examples, and best practices for each topic, making it a valuable resource for candidates preparing for technical interviews. The guide emphasizes important concepts and techniques necessary for effective Java programming and application development.

Uploaded by

Vipul
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Java & Spring Boot — Complete Interview Guide

Java & Spring Boot


Complete Interview Preparation Guide
Core Java • Spring Boot • Databases • Concurrency • Performance

Page 1 of 29
Java & Spring Boot — Complete Interview Guide

1. Stream API
The Stream API, introduced in Java 8, provides a functional approach to processing sequences of elements. It allows you to
perform operations like filter, map, reduce, collect etc. on collections in a declarative way — similar to SQL queries on data.

💡 A Stream is NOT a data structure. It does not store data. It is a pipeline of operations on a source (like a List or Array).

1.1 Stream Pipeline


Every stream pipeline has three parts:
• Source — where data comes from (List, Array, Set, etc.)
• Intermediate Operations — lazy operations that return a new Stream (filter, map, sorted, etc.)
• Terminal Operation — triggers the pipeline and produces a result (collect, forEach, reduce, count, etc.)

1.2 Common Operations with Examples


filter() — keep only matching elements
List<Integer> numbers = [Link](1, 2, 3, 4, 5, 6, 7, 8);

// Keep only even numbers


List<Integer> evens = [Link]()
.filter(n -> n % 2 == 0) // intermediate
.collect([Link]()); // terminal

// Output: [2, 4, 6, 8]

map() — transform each element


List<String> names = [Link]("alice", "bob", "charlie");

List<String> upper = [Link]()


.map(String::toUpperCase)
.collect([Link]());

// Output: ["ALICE", "BOB", "CHARLIE"]

reduce() — combine all elements into one


List<Integer> nums = [Link](1, 2, 3, 4, 5);

int sum = [Link]()

Page 2 of 29
Java & Spring Boot — Complete Interview Guide

.reduce(0, (a, b) -> a + b); // identity=0, accumulator

// Output: 15

collect() — gather results


// Group employees by department
Map<String, List<Employee>> byDept = [Link]()
.collect([Link](Employee::getDepartment));

// Join strings
String joined = [Link]()
.collect([Link](", ", "[", "]"));
// Output: [alice, bob, charlie]

flatMap() — flatten nested structures


List<List<Integer>> nested = [Link](
[Link](1, 2, 3),
[Link](4, 5, 6)
);

List<Integer> flat = [Link]()


.flatMap(Collection::stream)
.collect([Link]());

// Output: [1, 2, 3, 4, 5, 6]

1.3 Parallel Streams


// Use parallelStream() for CPU-intensive tasks on large datasets
long count = [Link]()
.filter(n -> isPrime(n))
.count();

// ⚠️ AVOID parallel streams for small lists or I/O-bound tasks


// The overhead of thread management can HURT performance on small data

⚠️Parallel streams use the ForkJoinPool. For shared mutable state, always use thread-safe collectors or stateless
operations.

Page 3 of 29
Java & Spring Boot — Complete Interview Guide

2. How to Implement Immutability


An immutable object is one whose state cannot be changed after it is created. Immutability is a key technique for writing
safe, predictable, and thread-safe code.

2.1 Rules to Create an Immutable Class


• Declare the class as final (prevents subclassing)
• Make all fields private and final
• No setter methods — only getters
• Initialize all fields via the constructor
• For mutable fields (like List, Date), return defensive copies in getters

2.2 Immutable Class Example


public final class ImmutableStudent {
private final String name;
private final int age;
private final List<String> courses; // mutable field — needs defensive copy

public ImmutableStudent(String name, int age, List<String> courses) {


[Link] = name;
[Link] = age;
// Defensive copy — so external changes don't affect us
[Link] = new ArrayList<>(courses);
}

public String getName() { return name; }


public int getAge() { return age; }

public List<String> getCourses() {


return [Link](courses); // Prevent modification via
getter
}
}

2.3 Java Record (Java 16+) — Automatic Immutability


// Records are immutable by default — the compiler generates everything
public record Student(String name, int age, List<String> courses) {
// Compact constructor for validation
public Student {

Page 4 of 29
Java & Spring Boot — Complete Interview Guide

if (age < 0) throw new IllegalArgumentException("Age cannot be


negative");
courses = [Link](courses); // defensive copy
}
}

Student s = new Student("Alice", 20, [Link]("Math", "Science"));


// [Link]() → Alice (getter auto-generated)
// [Link] = "Bob" → Compile error! Fields are final

💡 String, Integer, Long, Double, BigDecimal, and all wrapper types in Java are already immutable by design.

3. How to Create Custom Exceptions


Java has two types of exceptions: Checked (must be declared/caught) and Unchecked (RuntimeException subclasses). You
can create your own by extending the right base class.

3.1 Checked Custom Exception


// Checked exception — caller MUST handle or declare it
public class InsufficientFundsException extends Exception {
private final double amount;

public InsufficientFundsException(double amount) {


super("Insufficient funds. Short by: " + amount);
[Link] = amount;
}

// Constructor that wraps another exception (cause chaining)


public InsufficientFundsException(String message, Throwable cause) {
super(message, cause);
[Link] = 0;
}

public double getAmount() { return amount; }


}

3.2 Unchecked Custom Exception


// Unchecked exception — no need to declare or catch (but you can)
public class UserNotFoundException extends RuntimeException {

Page 5 of 29
Java & Spring Boot — Complete Interview Guide

private final Long userId;

public UserNotFoundException(Long userId) {


super("User not found with ID: " + userId);
[Link] = userId;
}

public Long getUserId() { return userId; }


}

// Usage in Service
public User findUser(Long id) {
return [Link](id)
.orElseThrow(() -> new UserNotFoundException(id));
}

3.3 Exception Hierarchy Best Practice


Type Extends When to Use

Checked Exception Recoverable conditions (file not found, network issues)

Unchecked RuntimeException Programming errors, invalid arguments, entity not


found

Error Error JVM-level issues — NEVER extend this in application


code

4. The final Keyword


The final keyword in Java can be applied to variables, methods, and classes — each with a distinct meaning.

4.1 final Variable


// final primitive — value cannot change
final int MAX_SIZE = 100;
MAX_SIZE = 200; // ❌ Compile error: cannot assign a value to final variable

// final reference — reference cannot change, but object state can!


final List<String> list = new ArrayList<>();
[Link]("Hello"); // ✅ OK — modifying the object
list = new ArrayList<>(); // ❌ Compile error — changing the reference

Page 6 of 29
Java & Spring Boot — Complete Interview Guide

4.2 final Method


public class Animal {
public final void breathe() {
[Link]("Breathing...");
}
}

public class Dog extends Animal {


@Override
public void breathe() { // ❌ Compile Error!
// Cannot override the final method from Animal
}
}

4.3 final Class


public final class MathUtils {
public static int square(int n) { return n * n; }
}

public class ExtendedMath extends MathUtils { // ❌ Compile Error!


// Cannot inherit from final class MathUtils
}

// Real-world example: String class is final


// That's why you can never extend String in Java

Context Error You Get

Reassigning a final variable error: cannot assign a value to final variable

Overriding a final method error: overridden method is final

Extending a final class error: cannot inherit from final ClassName

5. How to Process / Iterate Over Collections

5.1 All Ways to Iterate


List<String> fruits = [Link]("Apple", "Banana", "Cherry");

// ── 1. Classic for loop (index-based)

Page 7 of 29
Java & Spring Boot — Complete Interview Guide

for (int i = 0; i < [Link](); i++) {


[Link](i + ": " + [Link](i));
}

// ── 2. Enhanced for-each loop (most common)


for (String fruit : fruits) {
[Link](fruit);
}

// ── 3. Iterator (supports safe removal during iteration)


Iterator<String> it = [Link]();
while ([Link]()) {
String f = [Link]();
if ([Link]("Banana")) [Link](); // ✅ Safe removal
}

// ── 4. forEach with lambda (Java 8+)


[Link](fruit -> [Link](fruit));
[Link]([Link]::println); // method reference shorthand

// ── 5. Stream API
[Link]()
.filter(f -> [Link]("A"))
.forEach([Link]::println);

// ── 6. ListIterator (bidirectional — forward AND backward)


ListIterator<String> li = [Link]([Link]());
while ([Link]()) {
[Link]([Link]()); // Prints in reverse
}

5.2 Iterating Maps


Map<String, Integer> scores = new HashMap<>();
[Link]("Alice", 90);
[Link]("Bob", 85);

// ── entrySet() — most efficient, gives key+value together


for ([Link]<String, Integer> entry : [Link]()) {
[Link]([Link]() + " -> " + [Link]());
}

Page 8 of 29
Java & Spring Boot — Complete Interview Guide

// ── keySet() — iterate keys, fetch values separately (less efficient)


for (String key : [Link]()) {
[Link](key + " -> " + [Link](key));
}

// ── forEach (Java 8+) — cleanest


[Link]((name, score) -> [Link](name + " scored " + score));

6. Synchronized Keyword & Internal Mechanism


The synchronized keyword in Java is used to control access to shared resources in a multi-threaded environment. Without
synchronization, two threads can read/write the same variable simultaneously, causing data corruption (race conditions).

6.1 The Problem Without Synchronization


class Counter {
int count = 0;

void increment() { count++; } // count++ is NOT atomic!


// count++ is actually 3 steps: read, add, write
// Thread A reads count=5, Thread B reads count=5
// Thread A writes 6, Thread B writes 6 → Lost update!
}

6.2 Synchronized Method


class SafeCounter {
int count = 0;

// Only ONE thread can execute this at a time


public synchronized void increment() {
count++;
}

public synchronized int getCount() {


return count;
}
}

Page 9 of 29
Java & Spring Boot — Complete Interview Guide

// For static methods, the CLASS-level lock is used


public static synchronized void staticMethod() { ... }

6.3 Synchronized Block (Finer Granularity)


class BankAccount {
private double balance;
private final Object lock = new Object(); // Custom lock object

public void deposit(double amount) {


// Only lock the critical section, not the whole method
synchronized(lock) {
balance += amount;
}
// Other non-critical code runs without lock
}
}

6.4 Internal Mechanism — Monitor Lock (Intrinsic Lock)


Every Java object has a built-in monitor lock (also called intrinsic lock or mutex). Here is what happens internally:
• When a thread enters a synchronized method/block, it acquires the monitor lock of the object
• All other threads trying to acquire the SAME lock are blocked (put in WAITING state)
• When the thread exits, the lock is released and one waiting thread can proceed
• This is managed by the JVM using low-level OS primitives (like mutexes in POSIX)

💡 ReentrantLock from [Link] offers more features: tryLock(), timed lock, fairness policy. Prefer it for
complex scenarios.

7. Deadlock & How to Avoid It


A deadlock occurs when two or more threads are waiting for each other to release locks — resulting in all threads being
permanently blocked. It's like two people each holding one key the other needs.

7.1 Deadlock Example


Object lockA = new Object();
Object lockB = new Object();

Thread thread1 = new Thread(() -> {


synchronized (lockA) { // Thread1 acquires A

Page 10 of 29
Java & Spring Boot — Complete Interview Guide

[Link]("Thread1 holds A, waiting for B");


synchronized (lockB) { /* work */ } // Thread1 waits for B
}
});

Thread thread2 = new Thread(() -> {


synchronized (lockB) { // Thread2 acquires B
[Link]("Thread2 holds B, waiting for A");
synchronized (lockA) { /* work */ } // Thread2 waits for A
}
});

// RESULT: Thread1 waits for B (held by Thread2)


// Thread2 waits for A (held by Thread1) → DEADLOCK

7.2 How to Avoid Deadlock


• Lock Ordering: Always acquire locks in the SAME order in all threads
• Lock Timeout: Use tryLock(timeout) — give up if lock not acquired in time
• Avoid Nested Locks: Try not to hold multiple locks simultaneously
• Use Higher-Level Concurrency: Prefer [Link] (ConcurrentHashMap, Semaphore, etc.)
• Use Single Lock: If possible, use one lock for related resources

// Fix: Always acquire lockA BEFORE lockB in both threads


// Thread1: lockA → lockB
// Thread2: lockA → lockB (same order = no deadlock)

// Using tryLock to avoid indefinite waiting


ReentrantLock lockA = new ReentrantLock();
ReentrantLock lockB = new ReentrantLock();

boolean gotA = [Link](1, [Link]);


boolean gotB = [Link](1, [Link]);
if (gotA && gotB) {
try { /* do work */ }
finally { [Link](); [Link](); }
} else {
if (gotA) [Link]();
if (gotB) [Link]();
// Retry or handle gracefully
}

Page 11 of 29
Java & Spring Boot — Complete Interview Guide

8. How to Optimize Java Code

8.1 Use Appropriate Data Structures


// ❌ Wrong: using List for membership check — O(n)
List<String> bannedUsers = new ArrayList<>();
if ([Link](userId)) { ... } // Slow for large lists

// ✅ Better: use Set for O(1) lookup


Set<String> bannedUsers = new HashSet<>();
if ([Link](userId)) { ... } // Fast!

8.2 String Handling


// ❌ Wrong: String concatenation in a loop creates new String objects each time
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // Creates 1000 intermediate String objects!
}

// ✅ Correct: use StringBuilder


StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
[Link](i);
}
String result = [Link](); // One String created at the end

8.3 Avoid Unnecessary Object Creation


// ❌ Boxing/unboxing in loops is expensive
Long sum = 0L;
for (long i = 0; i < 1000000; i++) {
sum += i; // Auto-unbox + add + auto-box → 1 million object creations!
}

// ✅ Use primitive types


long sum = 0L;
for (long i = 0; i < 1000000; i++) {
sum += i; // Pure arithmetic, no boxing
}

Page 12 of 29
Java & Spring Boot — Complete Interview Guide

8.4 Use Lazy Initialization & Caching


// Compute expensive results once and cache them
private Map<String, Result> cache = new HashMap<>();

public Result compute(String input) {


return [Link](input, key -> expensiveOperation(key));
}

// Or use @Cacheable in Spring


@Cacheable("products")
public Product findProduct(Long id) {
return [Link](id).orElseThrow();
}

8.5 Other Key Optimization Tips


• Use try-with-resources to always close streams/connections properly
• Prefer Optional over null checks to avoid NullPointerException
• Use connection pooling (HikariCP) for database connections — never create raw connections
• Profile first with tools like VisualVM, JProfiler, or YourKit before optimizing
• Use int/long primitives instead of Integer/Long where possible in tight loops

9. How to Optimize a Spring Boot Application

9.1 Database Layer


• HikariCP Use connection pooling:
[Link]-pool-size=20
• Enable JPA second-level cache with Ehcache or Caffeine
• Use pagination: findAll(Pageable pageable) — never load all records at once
• Add @Transactional(readOnly=true) on read-only methods — improves performance
• Use projections (DTOs) instead of full entity fetch when you need only some fields

// ❌ Fetches ALL fields of ALL employees — very expensive


List<Employee> all = [Link]();

// ✅ Fetch only needed fields via DTO projection


public interface EmployeeNameOnly {
String getName();
String getEmail();
}

Page 13 of 29
Java & Spring Boot — Complete Interview Guide

List<EmployeeNameOnly> names = [Link]();

// ✅ Always paginate large queries


Page<Employee> page = employeeRepository
.findAll([Link](0, 20, [Link]("name")));

9.2 Caching
// Enable caching in main class
@SpringBootApplication
@EnableCaching
public class App { ... }

// Cache a service method


@Service
public class ProductService {
@Cacheable(value = "products", key = "#id")
public Product getProduct(Long id) {
return [Link](id).orElseThrow();
}

@CacheEvict(value = "products", key = "#id")


public void updateProduct(Long id, Product p) { ... }
}

9.3 Async Processing


@EnableAsync
@SpringBootApplication
public class App { ... }

@Service
public class EmailService {
@Async
public CompletableFuture<Void> sendEmail(String to) {
// This runs in a separate thread — doesn't block the main request
[Link](to);
return [Link](null);
}
}

Page 14 of 29
Java & Spring Boot — Complete Interview Guide

9.4 Other Spring Boot Optimizations


• Lazy bean loading: [Link]-initialization=true (speeds up startup)
• Use virtual threads (Java 21 + Spring Boot 3.2) for high concurrency
• Tune JVM: -Xms512m -Xmx2g -XX:+UseG1GC for better GC performance
• Use Actuator + Micrometer for real-time metrics monitoring
• Enable HTTP/2 for better connection multiplexing
• Compress responses: [Link]=true

10. Database Indexes & How They Help


An index is a separate data structure (usually a B-Tree) that the database maintains to allow fast lookups on a column —
without scanning every row. Think of it like the index at the back of a book.

10.1 Without Index vs With Index


-- Table with 1,000,000 rows
SELECT * FROM employees WHERE email = 'alice@[Link]';

-- WITHOUT index: Full Table Scan → checks all 1,000,000 rows (O(n))
-- WITH index on email: B-Tree Lookup → finds in ~20 comparisons (O(log n))

10.2 Creating Indexes


-- Single column index
CREATE INDEX idx_employee_email ON employees(email);

-- Composite index (covers multiple columns)


CREATE INDEX idx_emp_dept_sal ON employees(department, salary);
-- Best for queries filtering by department AND/OR salary

-- Unique index (also enforces uniqueness)


CREATE UNIQUE INDEX idx_unique_email ON employees(email);

-- In Spring/JPA using annotations


@Entity
@Table(name = "employees",
indexes = { @Index(name = "idx_email", columnList = "email") })
public class Employee { ... }

Page 15 of 29
Java & Spring Boot — Complete Interview Guide

10.3 Types of Indexes


Index Type Description Best Used For

B-Tree (default) Balanced tree, sorted data Range queries, equality, ORDER BY

Hash Index Hash map structure Equality lookups only (=)

Full-Text Index Tokenizes text content LIKE, MATCH AGAINST searches

Composite Index Multiple columns together Multi-column WHERE clauses

Covering Index All query columns in index Avoid table lookup entirely

10.4 When NOT to Index


• Small tables — full scan is often faster than index + lookup
• Columns with very low cardinality (e.g., a boolean 'is_active' column)
• Tables with very heavy write loads — indexes slow down INSERT/UPDATE/DELETE
⚠️Every index takes extra storage and slows down writes. Don't over-index — analyze your actual query patterns first
with EXPLAIN.

11. How to Optimize the Database

11.1 Query Optimization


-- ❌ SELECT * fetches ALL columns, even unused ones
SELECT * FROM orders WHERE customer_id = 100;

-- ✅ Select only what you need


SELECT id, total_amount, status FROM orders WHERE customer_id = 100;

-- ❌ Non-sargable query — index cannot be used


SELECT * FROM users WHERE YEAR(created_at) = 2024;

-- ✅ Sargable — can use index on created_at


SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-
01';

-- ❌ N+1 problem — 1 query for orders + N queries for each customer


-- ✅ Use JOIN instead
SELECT [Link], [Link], [Link]
FROM orders o JOIN customers c ON o.customer_id = [Link];

Page 16 of 29
Java & Spring Boot — Complete Interview Guide

11.2 Schema Optimization


• Use appropriate data types — VARCHAR(50) instead of TEXT for short strings
• Normalize to 3NF to eliminate data redundancy, but denormalize for read-heavy tables
• Archive old data — move historical records to archive tables
• Partition large tables by date or range to speed up queries

11.3 Connection & Configuration


• Enable query cache (for stable data) and connection pooling
• Set appropriate buffer sizes: innodb_buffer_pool_size to 70-80% of RAM (MySQL)
• Use read replicas to offload SELECT queries from the primary
• Run ANALYZE TABLE / VACUUM ANALYZE regularly to update statistics

12. Spring Bean Scopes


Bean scope defines how many instances of a bean Spring creates and how long they live.

Scope Instance Created Typical Use

singleton (default) ONE per Spring container Services, Repositories, Utilities

prototype NEW instance per injection/request Stateful beans, non-thread-safe objects

request ONE per HTTP request (web only) Request-specific data

session ONE per HTTP session (web only) User session data (shopping cart)

application ONE per ServletContext App-wide shared state

@Service
@Scope("singleton") // default — no annotation needed
public class OrderService { ... }

@Component
@Scope("prototype")
public class ReportGenerator {
// New instance each time it's injected — safe for stateful use
}

@Component
@RequestScope // shorthand for @Scope("request")
public class RequestContext {
private String requestId; // Fresh for every HTTP request
}

Page 17 of 29
Java & Spring Boot — Complete Interview Guide

⚠️Never inject a prototype bean into a singleton directly — the singleton captures one instance. Use
[Link]() or @Lookup method injection instead.

13. What is Persistence?


Persistence means saving data so it survives beyond the lifecycle of the application. When your app crashes or restarts,
persistent data is still available. In Java/Spring, JPA (Java Persistence API) is the standard way to persist data to a relational
database.

13.1 JPA Entity Example


@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

@Column(nullable = false, length = 200)


private String name;

@Column(precision = 10, scale = 2)


private BigDecimal price;

@ManyToOne(fetch = [Link]) // Load category only when accessed


@JoinColumn(name = "category_id")
private Category category;
}

13.2 JPA Entity Lifecycle States


State Description

Transient New object, not tracked by JPA, not in DB

Managed (Persistent) Tracked by EntityManager — changes auto-synced to DB

Detached Was managed, but EntityManager is closed — changes NOT tracked

Removed Marked for deletion — will be deleted on transaction commit

13.3 FetchType: EAGER vs LAZY


// LAZY — related data loaded only when you access it (preferred)

Page 18 of 29
Java & Spring Boot — Complete Interview Guide

@OneToMany(fetch = [Link])
private List<Order> orders;

// EAGER — related data loaded immediately with the parent


@ManyToOne(fetch = [Link])
private Department department;

// ⚠️ LAZY can cause LazyInitializationException outside a transaction


// Fix: use @Transactional on service methods, or use JOIN FETCH in JPQL
@Query("SELECT e FROM Employee e JOIN FETCH [Link] WHERE [Link] = :id")
Optional<Employee> findWithDepartment(@Param("id") Long id);

14. Use Cases of Sync and Async Calls

Aspect Synchronous Asynchronous

Execution Caller waits for response Caller continues immediately

Thread Usage Thread blocked while waiting Thread freed while waiting

Error Handling Direct exception propagation Handled via callbacks/CompletableFuture

Use Case Simple, sequential workflows Long tasks, I/O operations, notifications

14.1 Synchronous Example


// Sync: caller waits until payment completes
public OrderResponse placeOrder(OrderRequest req) {
[Link]([Link]()); // blocks here
[Link]([Link]()); // then this runs
return [Link](buildOrder(req));
}
// Total time = payment time + inventory time + save time

14.2 Asynchronous Example


// Async: fire and forget for non-critical tasks
@Async
public void sendWelcomeEmail(String userEmail) {
// Runs in background thread — doesn't slow down registration
[Link](userEmail, "Welcome!");
}

Page 19 of 29
Java & Spring Boot — Complete Interview Guide

// Async with result — CompletableFuture


public CompletableFuture<ProductInfo> getProductInfo(Long id) {
return [Link](() -> [Link](id));
}

// Combine multiple async calls


CompletableFuture<ProductInfo> productFuture = getProductInfo(1L);
CompletableFuture<StockInfo> stockFuture = getStockInfo(1L);

[Link](productFuture, stockFuture).thenRun(() -> {


// Both complete — runs in parallel!
ProductInfo p = [Link]();
StockInfo s = [Link]();
});

15. How API Gateway Mitigates Failures


An API Gateway sits in front of your microservices and acts as the single entry point. It handles cross-cutting concerns so
individual services don't have to.

15.1 Key Failure Mitigation Patterns


• Rejects excessive requests (e.g., max 1000 req/min per client). Prevents [Link] Limiting:
• If a downstream service fails N times in a row, stop calling it temporarily. Fail [Link] Breaker:
• Automatically retry failed requests with exponential [Link] with Backoff:
• If a service takes too long (e.g., >5s), return an error instead of [Link]:
• Distributes requests across multiple instances of a [Link] Balancing:
• Rejects malformed requests before they reach [Link] Validation:
• Handles JWT validation centrally — services trust the [Link]/Authorization:

# Spring Cloud Gateway example config ([Link])


spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE # load balanced
predicates:
- Path=/api/users/**
filters:

Page 20 of 29
Java & Spring Boot — Complete Interview Guide

- name: CircuitBreaker
args:
name: userServiceCB
fallbackUri: forward:/fallback/users
- name: RequestRateLimiter
args:
[Link]: 100
[Link]: 200

16. Primary Key vs Unique Key

Aspect Primary Key Unique Key

Purpose Uniquely identifies each row Ensures column values are unique

NULL allowed? NO — cannot be NULL YES — can have one NULL (most DBs)

Count per table Only ONE per table Multiple unique keys allowed

Index created Clustered index (in MySQL) Non-clustered index

Implicit constraint Also enforces NOT NULL Only uniqueness

Example [Link] [Link]

CREATE TABLE employees (


id INT PRIMARY KEY AUTO_INCREMENT, -- Primary Key
email VARCHAR(100) UNIQUE NOT NULL, -- Unique Key
pan_number VARCHAR(20) UNIQUE, -- Another Unique Key
name VARCHAR(100) NOT NULL
);

-- You can have a COMPOSITE primary key


CREATE TABLE enrollment (
student_id INT,
course_id INT,
PRIMARY KEY (student_id, course_id) -- Together they're unique
);

17. Spring Boot Default Server


By default, Spring Boot uses Tomcat as its embedded web server. It is auto-configured when you include spring-boot-
starter-web in your [Link]. The default port is 8080.

Page 21 of 29
Java & Spring Boot — Complete Interview Guide

17.1 Switching Embedded Servers


<!-- [Link]: Exclude Tomcat and add Jetty instead -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

# [Link]
[Link]=8080 # Default
[Link]=200 # Max request threads
[Link]-connections=10000

Server Best For

Tomcat (default) General purpose — most widely used, great community support

Jetty High concurrency, lighter weight, good for embedded use

Undertow Highest throughput, non-blocking, used by WildFly

Netty (WebFlux only) Reactive/non-blocking apps with Spring WebFlux

18. @EnableAutoConfiguration
@EnableAutoConfiguration tells Spring Boot to automatically configure your application based on the JARs on your
classpath. If you have spring-data-jpa on the classpath, it auto-configures a DataSource, EntityManagerFactory,
TransactionManager etc.

// @SpringBootApplication is a combination of 3 annotations:


@SpringBootApplication
// equals:
@Configuration // marks class as bean definition source

Page 22 of 29
Java & Spring Boot — Complete Interview Guide

@ComponentScan // scans for @Component, @Service, @Repository,


@Controller
@EnableAutoConfiguration // enables auto-configuration magic

// Spring Boot reads META-INF/spring/[Link].


// [Link] to find all auto-config classes

// Example: DataSourceAutoConfiguration runs if:


// 1. [Link] is on classpath
// 2. No DataSource bean is already defined

// To exclude a specific auto-configuration


@SpringBootApplication(exclude = { [Link] })
public class App { ... }

// Or via properties
//
[Link]=[Link]
ceAutoConfiguration

💡 You can see all auto-configurations triggered on startup by adding --debug flag or setting
[Link]=DEBUG

19. ConcurrentModificationException
This exception is thrown when you modify a collection (add/remove elements) while iterating over it with a for-each or
Iterator. Java's collection iterators have a 'fail-fast' mechanism — they maintain a modCount. Any structural change
increments modCount, and the iterator checks it on every next() call.

19.1 How It Happens


List<String> names = new ArrayList<>([Link]("Alice", "Bob", "Charlie"));

// ❌ This will throw ConcurrentModificationException


for (String name : names) {
if ([Link]("Bob")) {
[Link](name); // Modifying while iterating!
}
}

19.2 How to Fix It


// ✅ Fix 1: Use [Link]()

Page 23 of 29
Java & Spring Boot — Complete Interview Guide

Iterator<String> it = [Link]();
while ([Link]()) {
if ([Link]().equals("Bob")) {
[Link](); // Safe removal through the iterator
}
}

// ✅ Fix 2: Use removeIf() (Java 8+) — cleanest


[Link](name -> [Link]("Bob"));

// ✅ Fix 3: Collect to remove list, then remove


List<String> toRemove = [Link]()
.filter(n -> [Link]("Bob"))
.collect([Link]());
[Link](toRemove);

// ✅ Fix 4: For multi-threaded access, use CopyOnWriteArrayList


List<String> safeList = new CopyOnWriteArrayList<>(names);
// Creates a fresh copy on every write — safe but memory-intensive

20. HTTP Error Codes: 500, 502, 415

Code Name Meaning Common Cause

500 Internal Server Error Server crashed / unhandled NullPointerException, DB connection


exception failure, bug in code

502 Bad Gateway Upstream server sent invalid Downstream microservice down, load
response balancer issue, timeout

415 Unsupported Media Server rejects content format Missing Content-Type: application/json
Type header, sending XML to JSON endpoint

20.1 Understanding Each Error


500 — Internal Server Error
// Cause: unhandled exception in your code
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return [Link](id); // throws NullPointerException → 500
}

Page 24 of 29
Java & Spring Boot — Complete Interview Guide

// Fix: global exception handler


@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
[Link]("Unexpected error", ex);
return [Link](500)
.body(new ErrorResponse("Internal server error"));
}
}

502 — Bad Gateway


// Cause: Service B is down when Service A calls it via API Gateway
// Service A → API Gateway → Service B (DOWN) → 502 returned to client

// Fix: Add circuit breaker + fallback


@CircuitBreaker(name = "userService", fallbackMethod = "fallbackUser")
public User getUserFromService(Long id) {
return [Link]("/user/" + id, [Link]);
}

public User fallbackUser(Long id, Throwable t) {


return new User(id, "Unknown"); // graceful degradation
}

415 — Unsupported Media Type


// Cause: Client sends request without correct Content-Type header

// curl without Content-Type → 415


// curl -X POST [Link] -d '{"name":"Alice"}'

// curl WITH Content-Type → works


// curl -X POST [Link]
// -H 'Content-Type: application/json'
// -d '{"name":"Alice"}'

// In Spring, specify what you accept:


@PostMapping(value = "/users", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> createUser(@RequestBody User user) { ... }

Page 25 of 29
Java & Spring Boot — Complete Interview Guide

21. How to Do Query Optimization

21.1 Use EXPLAIN to Understand the Plan


-- Run EXPLAIN before optimizing any query
EXPLAIN SELECT * FROM orders WHERE customer_id = 100 AND status = 'PENDING';

-- Look for:
-- type = ALL → Full table scan (BAD)
-- type = ref or range → Index used (GOOD)
-- rows → estimated rows scanned (lower is better)
-- Extra = 'Using filesort' → expensive sort (add index)
-- Extra = 'Using temporary' → temp table used (consider rewriting)

21.2 Optimization Techniques


-- ❌ Using function on indexed column — breaks index usage
SELECT * FROM users WHERE LOWER(email) = 'alice@[Link]';

-- ✅ Store data in consistent case, query directly


SELECT * FROM users WHERE email = 'alice@[Link]';

-- ❌ LIKE with leading wildcard — full scan


SELECT * FROM products WHERE name LIKE '%phone%';

-- ✅ Use Full-Text search instead


SELECT * FROM products WHERE MATCH(name) AGAINST ('phone');

-- ❌ Subquery in WHERE — runs for every row


SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE
country='IN');

-- ✅ Use JOIN instead


SELECT o.* FROM orders o
JOIN customers c ON o.customer_id = [Link]
WHERE [Link] = 'IN';

-- ❌ Implicit conversion breaks index


SELECT * FROM users WHERE phone_number = 9876543210; -- numeric on VARCHAR column

-- ✅ Use quotes for string columns

Page 26 of 29
Java & Spring Boot — Complete Interview Guide

SELECT * FROM users WHERE phone_number = '9876543210';

21.3 N+1 Problem in JPA (Very Common in Spring)


// ❌ N+1: 1 query for all orders + N queries for each customer
List<Order> orders = [Link]();
[Link](o -> [Link]([Link]().getName())); // N extra
queries!

// ✅ Fix: JOIN FETCH in JPQL — single query fetches everything


@Query("SELECT o FROM Order o JOIN FETCH [Link]")
List<Order> findAllWithCustomer();

// ✅ Or use @EntityGraph
@EntityGraph(attributePaths = {"customer"})
List<Order> findAll();

22. Garbage Collection in Java


Java manages memory automatically through Garbage Collection (GC). The GC identifies objects that are no longer
reachable (no live references) and reclaims their memory. You don't call free() like in C — the JVM handles it.

22.1 JVM Memory Regions


Region What's Stored GC Involvement

Eden Space (Young Gen) Newly created objects Minor GC — very frequent, fast

Survivor Spaces (S0, S1) Objects that survived one GC cycle Objects promoted between S0/S1

Old Gen (Tenured) Long-lived objects Major GC — less frequent, slower

Metaspace Class metadata, static vars Full GC only

Stack Method frames, local primitives No GC — auto-managed per thread

22.2 GC Algorithms
GC Type Flag Best For

Serial GC -XX:+UseSerialGC Single-threaded, small heaps

Parallel GC (default <Java9) -XX:+UseParallelGC Throughput-focused batch apps

G1 GC (default Java 9+) -XX:+UseG1GC Balanced latency + throughput (most apps)

ZGC (Java 15+) -XX:+UseZGC Ultra-low latency, large heaps (TB scale)

Page 27 of 29
Java & Spring Boot — Complete Interview Guide

Shenandoah -XX:+UseShenandoahGC Low-pause, concurrent GC

22.3 How to Help the GC (Best Practices)


// ✅ Nullify large objects when no longer needed
byte[] largeBuffer = readFile(path);
process(largeBuffer);
largeBuffer = null; // Eligible for GC sooner

// ✅ Use try-with-resources — closes & derefs connection/stream


try (Connection conn = [Link]()) {
// conn auto-closed at end, eligible for GC
}

// ✅ Avoid memory leaks — common causes:


// - Static collections holding references: static List<Object> cache = ...
// - Event listeners not unregistered
// - ThreadLocal not removed after use

// Always clean up ThreadLocal


[Link](value);
try { doWork(); }
finally { [Link](); } // Prevent memory leak

// ✅ JVM tuning flags


// -Xms512m → initial heap size
// -Xmx4g → max heap size
// -XX:+UseG1GC → use G1 garbage collector
// -XX:MaxGCPauseMillis=200 → target max GC pause

22.4 Monitoring GC
// Enable GC logging (Java 9+)
// -Xlog:gc*:file=/var/log/app/[Link]:time,uptime:filecount=5,filesize=20m

// Programmatically trigger GC (suggestion only — JVM may ignore)


[Link](); // Not recommended in production!

// Use Spring Boot Actuator + Micrometer for GC metrics


// GET /actuator/metrics/[Link] → shows GC pause times
// GET /actuator/metrics/[Link] → current memory usage

Page 28 of 29
Java & Spring Boot — Complete Interview Guide

💡 For production Spring Boot apps: Use -XX:+UseG1GC -Xms1g -Xmx4g -XX:MaxGCPauseMillis=200. Monitor with
Actuator or Prometheus/Grafana.

— End of Guide —

Page 29 of 29

You might also like