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

Java Interview Prep Guide

This document is a preparation guide for a Java Senior Developer interview, containing 50 interview questions and answers covering core Java concepts, Spring Framework, design patterns, and more. Key topics include differences between Java versions, functional interfaces, exception handling, dependency injection in Spring, Spring Boot auto-configuration, and various design patterns like Singleton and Strategy. It provides practical examples and explanations to help candidates prepare effectively for technical interviews.

Uploaded by

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

Java Interview Prep Guide

This document is a preparation guide for a Java Senior Developer interview, containing 50 interview questions and answers covering core Java concepts, Spring Framework, design patterns, and more. Key topics include differences between Java versions, functional interfaces, exception handling, dependency injection in Spring, Spring Boot auto-configuration, and various design patterns like Singleton and Strategy. It provides practical examples and explanations to help candidates prepare effectively for technical interviews.

Uploaded by

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

Java Senior Developer Interview

Preparation Guide
50 Interview Questions & Answers

Core Java & Language Fundamentals


Q1: What are the key differences between Java 8 and
Java 11/17? Explain Stream API improvements.
Answer:
Java 8 introduced functional programming paradigms, while Java
11/17 enhanced performance and security[1].
Key Differences:

Streams API (Java 8): Introduced functional-style operations on


collections using map(), filter(), reduce()
Module System (Java 9): Project Jigsaw introduced modules for
better code organization
Local Variable Type Inference (Java 10): var keyword for local
variables
Records (Java 14+): Immutable data classes with minimal
boilerplate
Sealed Classes (Java 15+): Restrict class inheritance for better
type safety
Text Blocks (Java 13+): Multiline strings with proper formatting
Pattern Matching (Java 16+): Simplified control flow with
pattern matching
Stream API Improvements:
// Java 8
List<String> names = [Link]()
.filter(p -> [Link]() > 18)
.map(Person::getName)
.collect([Link]());
// Java 16+ with pattern matching
if (obj instanceof String s) {
[Link]([Link]());
}

Q2: Explain the concept of Functional Interfaces and


provide examples.
Answer:
A Functional Interface is an interface with exactly ONE abstract
method. It enables functional programming in Java.
Characteristics:

Can have multiple default methods or static methods


Only ONE abstract method (SAM - Single Abstract Method)
Marked with @FunctionalInterface annotation (optional but
recommended)
Common Built-in Functional Interfaces:

Predicate<T>: Takes T, returns boolean


Function<T, R>: Takes T, returns R
Consumer<T>: Takes T, returns void
Supplier<T>: Takes nothing, returns T
BiFunction<T, U, R>: Takes T and U, returns R
Example Implementation:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
// Usage with Lambda
Calculator add = (a, b) -> a + b;
int result = [Link](5, 3); // Returns 8
// With Stream API
List<Integer> numbers = [Link](1, 2, 3, 4, 5);
[Link]()
.filter(n -> n > 2) // Predicate
.map(n -> n * 2) // Function
.forEach([Link]::println); // Consumer

Q3: What are the differences between abstract classes


and interfaces? When would you use each?
Answer:
While both define contracts, they serve different purposes:

Aspect Abstract Class Interface


Construct
Can have Cannot have
or
Can have instance Only constants (Java 8+: can
State
variables have private fields)
Can be public,
Methods Public/private (Java 9+)
protected, private
Inheritanc
Single inheritance Multiple inheritance
e
Access Can use all Methods are public by
Modifiers modifiers default
Use Case "IS-A" relationship "CAN-DO" capability

When to Use Abstract Class:

When classes share common code/state


When you need non-public members
When you want to control access to inherited members
When to Use Interface:

Define a contract/capability for unrelated classes


Multiple inheritance needed
Define constants for related classes
Practical Example:
// Abstract Class - IS-A
abstract class Animal {
private String name;
abstract void makeSound();
public void sleep() { [Link]("Sleeping..."); }
}
// Interface - CAN-DO
interface Flyable {
void fly();
}
class Bird extends Animal implements Flyable {
@Override
public void makeSound() { [Link]("Tweet!"); }
@Override
public void fly() { [Link]("Flying..."); }
}

Q4: Explain the difference between checked and


unchecked exceptions. Provide examples.
Answer:
Exceptions in Java are categorized based on whether they must be
handled at compile-time.
Checked Exceptions:

Must be caught or declared in method signature


Subclass of Exception (but not RuntimeException)
Examples: IOException, SQLException, ClassNotFoundException
Checked at compile-time
Unchecked Exceptions:

Don't need to be caught or declared


Subclass of RuntimeException
Examples: NullPointerException,
ArrayIndexOutOfBoundsException, ClassCastException
Checked at runtime
Code Example:
// Checked Exception - MUST handle
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // Throws IOException
[Link]();
}
// Unchecked Exception - Not required to handle
public void accessArray(int[] arr, int index) {
[Link](arr[index]); // May throw
ArrayIndexOutOfBoundsException
}
// Best Practice - Use try-catch for both
try {
readFile("[Link]");
} catch (IOException e) {
[Link]("File read failed", e);
}

Spring Framework & Dependency Injection


Q5: Explain Dependency Injection (DI) and its benefits.
How does Spring implement it?
Answer:
Dependency Injection is a design pattern that provides dependencies
to an object rather than having the object create them. This promotes
loose coupling and testability.
Types of DI in Spring:

1. Constructor Injection (Recommended)


@Component
public class UserService {
private final UserRepository repository;
@Autowired
public UserService(UserRepository repository) {
[Link] = repository;
}
}
2. Setter Injection
@Component
public class UserService {
private UserRepository repository;
@Autowired
public void setRepository(UserRepository repository) {
[Link] = repository;
}
}
3. Field Injection (Not recommended - harder to test)
@Component
public class UserService {
@Autowired
private UserRepository repository;
}
Benefits:

Loose Coupling: Components don't depend on concrete


implementations
Testability: Easy to inject mock dependencies
Flexibility: Dependencies can be swapped easily
Maintainability: Changes don't cascade through code
Inversion of Control: Framework manages object lifecycle

Q6: What is the Spring Bean lifecycle? Explain the


different phases.
Answer:
Spring Bean lifecycle consists of several phases from instantiation to
destruction.
Phases:

1. Instantiation: Container creates bean instance


2. Populate Properties: Dependency injection occurs
3. Aware Methods: If bean implements *Aware interfaces
[Link]()
[Link]()
4. Post-Processing Before Init:
[Link]()
5. Init Methods:
@PostConstruct annotation
[Link]()
Custom init-method
6. Post-Processing After Init:
[Link]()
7. Usage: Bean available for use
8. Destruction:
@PreDestroy annotation
[Link]()
Custom destroy-method
Code Example:
@Component
public class MyBean implements InitializingBean, DisposableBean {
@PostConstruct
public void init() {
[Link]("Post construct");
}
@Override
public void afterPropertiesSet() throws Exception {
[Link]("After properties set");
}
@PreDestroy
public void cleanup() {
[Link]("Pre destroy");
}
@Override
public void destroy() throws Exception {
[Link]("Destroy");
}
}

Q7: Explain Spring Bean Scopes. What's the difference


between singleton and prototype?
Answer:
Bean scope defines the lifecycle and visibility of bean instances.
Available Scopes:

1. Singleton (Default)
One instance per Spring container
Thread-safe if beans are stateless
Suitable for stateless services
@Component
@Scope("singleton")
public class UserService { }
2. Prototype
New instance created each time
Not managed by container after creation
Suitable for stateful beans
@Component
@Scope("prototype")
public class RequestContext { }
3. Web Scopes (Web applications only)
Request: New instance per HTTP request
Session: Instance per user session
Application: Singleton at servlet context level
WebSocket: One instance per WebSocket session

Comparison:
// Singleton - Safe for stateless operations
@Service // Singleton by default
public class UserService {
private UserRepository repository;
public User findById(Long id) {
return [Link](id);
}
}
// Prototype - For stateful objects
@Component
@Scope("prototype")
public class RequestProcessor {
private String requestData;
public void process(String data) {
[Link] = data;
}
}

Q8: What is Aspect-Oriented Programming (AOP) in


Spring? Provide real-world examples.
Answer:
AOP allows you to modularize cross-cutting concerns (logging,
security, transactions) separate from business logic.
Key Concepts:

Aspect: Module containing cross-cutting concern


Pointcut: Expression to identify join points
Join Point: Execution point (method call)
Advice: Action taken at join point (Before, After, Around, etc.)
Weaving: Process of applying aspects to objects

Real-World Examples:

1. Logging Aspect
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* [Link]..(..))")
public void logBeforeMethod(JoinPoint joinPoint) {
String methodName = [Link]().getName();
[Link]("Executing method: " + methodName);
}
}
2. Performance Monitoring
@Aspect
@Component
public class PerformanceAspect {
@Around("execution(* [Link]..(..))")
public Object monitorPerformance(ProceedingJoinPoint joinPoint)
throws Throwable {
long startTime = [Link]();
Object result = [Link]();
long endTime = [Link]();
long duration = endTime - startTime;

[Link]("Method " + [Link]().getName() +


" took " + duration + "ms");
return result;

}
}
3. Transaction Management (Declarative)
@Service
public class UserService {
@Transactional
public void saveUser(User user) {
[Link](user);
}
}
Advice Types:

@Before: Execute before method


@After: Execute after method (always)
@AfterReturning: Execute after successful return
@AfterThrowing: Execute if exception thrown
@Around: Execute before and after method
Q9: Explain Spring Boot and its auto-configuration. How
does it differ from traditional Spring?
Answer:
Spring Boot simplifies Spring application development through
intelligent defaults and automated configuration.
Key Differences:

Aspect Spring Spring Boot


XML/Java config
Configuration Auto-configuration
required
Dependency Starter
Manual
Management dependencies
Need external Embedded
Embedded Server
server (Tomcat/Jetty)
Deployment WAR file Executable JAR
Performance Slower startup Faster startup

Auto-Configuration in Spring Boot:


@SpringBootApplication // Combines:
// @Configuration
// @ComponentScan
// @EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
[Link]([Link], args);
}
}
How Auto-Configuration Works:

1. Spring Boot scans classpath for specific libraries


2. Applies @ConditionalOn* annotations
3. Activates pre-configured beans if conditions met
4. User can override with custom configuration
Example Auto-Configuration:
// In [Link]
@Configuration
@ConditionalOnClass([Link])
@ConditionalOnProperty(name = "[Link]")
public class DataSourceAutoConfiguration {
@Bean
public DataSource dataSource() {
// Automatically creates DataSource
}
}
Overriding Auto-Configuration:

[Link]
[Link]=jdbc:mysql://localhost:3306/mydb
[Link]-class-name=[Link]

Q10: Explain Spring MVC request/response lifecycle.


How does DispatcherServlet work?
Answer:
Spring MVC follows Front Controller pattern where DispatcherServlet
handles all requests.
Request Processing Flow:

1. HTTP Request: Browser sends request


2. DispatcherServlet: Receives request
3. HandlerMapping: Identifies appropriate controller
4. Handler: Controller method processes request
5. Model: Controller returns model with data
6. View: ViewResolver determines view template
7. Rendering: View renders with model data
8. HTTP Response: Browser receives response
Code Example:
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable Long id, Model model) {
User user = [Link](id);
[Link]("user", user);
return "user-detail"; // View name
}
@PostMapping
public String createUser(@ModelAttribute User user) {
[Link](user);
return "redirect:/users";
}
}
DispatcherServlet Configuration:

dispatcher
[Link]
dispatcher /

Software Design Patterns


Q11: Explain the Singleton pattern and its thread-safety
implications.
Answer:
Singleton ensures only ONE instance of a class exists throughout the
application lifetime.
Implementation Approaches:

1. Eager Initialization (Thread-Safe but wastes memory)


public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return instance;
}
}
2. Lazy Initialization with Synchronized (Slow)
public class Singleton {
private static Singleton instance;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3. Double-Checked Locking (Recommended)
public class Singleton {
private static volatile Singleton instance;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
synchronized ([Link]) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
4. Bill Pugh Singleton (Best - Thread-safe and lazy)
public class Singleton {
private Singleton() { }
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return [Link];
}
}
5. Enum Singleton (Most secure, prevents reflection attacks)
public enum Singleton {
INSTANCE;
public void doSomething() {
[Link]("Doing something");
}
}
// Usage
[Link]();

Q12: Compare Factory pattern, Builder pattern, and


Abstract Factory pattern.
Answer:

Factory Pattern: Creates objects without specifying exact classes.


interface Animal { void makeSound(); }
class Dog implements Animal {
public void makeSound() { [Link]("Woof!"); }
}
class Cat implements Animal {
public void makeSound() { [Link]("Meow!"); }
}
class AnimalFactory {
public static Animal createAnimal(String type) {
return "DOG".equals(type) ? new Dog() : new Cat();
}
}
// Usage
Animal dog = [Link]("DOG");
Builder Pattern: Constructs complex objects step by step.
public class House {
private String foundation;
private String walls;
private String roof;
public static class Builder {
private String foundation;
private String walls;
private String roof;

public Builder foundation(String f) {


[Link] = f;
return this;
}

public Builder walls(String w) {


[Link] = w;
return this;
}

public Builder roof(String r) {


[Link] = r;
return this;
}

public House build() {


House house = new House();
[Link] = [Link];
[Link] = [Link];
[Link] = [Link];
return house;
}
}
}
// Usage
House house = new [Link]()
.foundation("Concrete")
.walls("Brick")
.roof("Tiles")
.build();
Abstract Factory Pattern: Creates families of related objects.
interface UIFactory {
Button createButton();
TextField createTextField();
}
class WindowsUIFactory implements UIFactory {
public Button createButton() { return new WindowsButton(); }
public TextField createTextField() { return new WindowsTextField(); }
}
class MacUIFactory implements UIFactory {
public Button createButton() { return new MacButton(); }
public TextField createTextField() { return new MacTextField(); }
}
Comparison:

Factory: Single object creation


Builder: Complex object construction step-by-step
Abstract Factory: Family of related objects

Q13: Explain the Strategy pattern and provide practical


examples.
Answer:
Strategy pattern allows selecting algorithm behavior at runtime.
Implementation:
// Strategy Interface
public interface PaymentStrategy {
void pay(double amount);
}
// Concrete Strategies
public class CreditCardPayment implements PaymentStrategy {
public void pay(double amount) {
[Link]("Paid " + amount + " via Credit Card");
}
}
public class UPIPayment implements PaymentStrategy {
public void pay(double amount) {
[Link]("Paid " + amount + " via UPI");
}
}
public class CryptoPayment implements PaymentStrategy {
public void pay(double amount) {
[Link]("Paid " + amount + " via Cryptocurrency");
}
}
// Context
public class ShoppingCart {
private PaymentStrategy strategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
[Link] = strategy;
}
public void checkout(double totalAmount) {
[Link](totalAmount);
}
}
// Usage
ShoppingCart cart = new ShoppingCart();
[Link](new CreditCardPayment());
[Link](5000); // Paid 5000 via Credit Card
[Link](new UPIPayment());
[Link](3000); // Paid 3000 via UPI
Real-World Use Cases:

Payment methods in e-commerce


Sorting algorithms
Caching strategies
Compression algorithms
Authentication methods

Q14: Explain the Observer pattern. How is it


implemented in Java and Spring?
Answer:
Observer pattern defines one-to-many relationship where subjects
notify observers of state changes.
Core Implementation:
// Observer Interface
public interface Observer {
void update(String event);
}
// Subject (Observable)
public class EventPublisher {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
[Link](observer);
}
public void detach(Observer observer) {
[Link](observer);
}
public void notifyObservers(String event) {
for (Observer observer : observers) {
[Link](event);
}
}
public void publishEvent(String event) {
notifyObservers(event);
}
}
// Concrete Observers
public class EmailObserver implements Observer {
@Override
public void update(String event) {
[Link]("Sending email: " + event);
}
}
public class LogObserver implements Observer {
@Override
public void update(String event) {
[Link]("Logging: " + event);
}
}
Spring Event Implementation (Preferred):
// Custom Event
public class UserCreatedEvent extends ApplicationEvent {
private String userId;
public UserCreatedEvent(Object source, String userId) {
super(source);
[Link] = userId;
}
public String getUserId() { return userId; }
}
// Publisher
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void createUser(User user) {
[Link](user);
[Link](new UserCreatedEvent(this,
[Link]()));
}
}
// Listeners
@Component
public class EmailListener {
@EventListener
public void onUserCreated(UserCreatedEvent event) {
[Link]("Sending welcome email for user: " +
[Link]());
}
}
@Component
public class NotificationListener {
@EventListener
public void onUserCreated(UserCreatedEvent event) {
[Link]("Creating notification for user: " +
[Link]());
}
}

Testing & Code Quality


Q15: Explain unit testing best practices. How would you
test Spring beans?
Answer:
Unit testing ensures code reliability and maintainability.
Best Practices:

1. Arrange-Act-Assert (AAA): Setup test data, execute code, verify


results
2. One assertion per test (or closely related assertions)
3. Descriptive test names: Test methods should indicate what
they test
4. Isolation: Tests should be independent
5. Mock external dependencies: Use mocks for databases, APIs,
etc.
Testing Spring Beans:
@ExtendWith([Link])
public class UserServiceTest {
@Mock
private UserRepository repository;
@InjectMocks
private UserService service;
@Test
void testFindUserById() {
// Arrange
Long userId = 1L;
User expectedUser = new User(userId, "John Doe", "
john@[Link]");
when([Link](userId)).thenReturn([Link](expectedU
ser));

// Act
User actualUser = [Link](userId);

// Assert
assertEquals([Link](), [Link]());
assertEquals("John Doe", [Link]());
verify(repository, times(1)).findById(userId);

}
@Test
void testFindUserByIdNotFound() {
// Arrange
Long userId = 999L;
when([Link](userId)).thenReturn([Link]());

// Act & Assert


assertThrows([Link], () -> [Link](userId));

}
@Test
void testSaveUser() {
// Arrange
User user = new User(null, "Jane Doe", "jane@[Link]");
User savedUser = new User(1L, "Jane Doe", "jane@[Link]");
when([Link](any([Link]))).thenReturn(savedUser);

// Act
User result = [Link](user);

// Assert
assertNotNull([Link]());
assertEquals("Jane Doe", [Link]());
verify(repository, times(1)).save(any([Link]));

}
}
Integration Testing:
@SpringBootTest
public class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setup() {
[Link]();
}
@Test
void testCreateAndRetrieveUser() {
// Arrange
User user = new User(null, "Test User", "test@[Link]");
// Act
User savedUser = [Link](user);
User retrievedUser = [Link]([Link]());

// Assert
assertEquals([Link](), [Link]());
assertEquals("Test User", [Link]());

}
}

Database & Data Access


Q16: Explain the difference between JPA/Hibernate and
JDBC. When would you use each?
Answer:
Both provide database access but at different abstraction levels.
JPA/Hibernate (ORM - Object-Relational Mapping):

Pros: Object-oriented, automatic mapping, less boilerplate


Cons: Performance overhead, N+1 query problems, query
debugging harder
Use When: Standard CRUD operations, complex mappings, rapid
development
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
@Column(name = "email")
private String email;
@OneToMany(mappedBy = "user")
private List<Order> orders;
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
// Usage
User user = [Link]("john@[Link]");
JDBC (Low-level):

Pros: Fine-grained control, predictable SQL, better performance


Cons: More boilerplate, manual mapping, prone to errors

public class UserJdbcRepository {


@Autowired
private JdbcTemplate jdbcTemplate;
public User findById(Long id) {
String sql = "SELECT * FROM users WHERE id = ?";
return [Link](sql, new Object[]{id},
new UserRowMapper());
}
public void save(User user) {
String sql = "INSERT INTO users (email, name) VALUES (?, ?)";
[Link](sql, [Link](), [Link]());
}
}
class UserRowMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException
{
User user = new User();
[Link]([Link]("id"));
[Link]([Link]("email"));
[Link]([Link]("name"));
return user;
}
}
Comparison:

Feature JPA/Hibernate JDBC


Abstraction High Low
Boilerplate Low High
Performance Good (with tuning) Excellent
Flexibility Limited High
Learning Curve Steep Gentle

Q17: Explain Spring Data JPA and write a complex query


example.
Answer:
Spring Data JPA simplifies data access layer with automatic
repository implementation.
Features:

Automatic query generation from method names


JPQL and native SQL query support
Pagination and sorting
Custom repository implementations
Complex Query Example:
@Repository
public interface OrderRepository extends JpaRepository<Order,
Long> {
// Query method
List<Order> findByUserIdAndStatusOrderByCreatedDateDesc(Long
userId, String status);
// JPQL Query
@Query("SELECT o FROM Order o WHERE [Link] = ?1 AND [Link]
= ?2")
List<Order> findUserOrders(Long userId, String status);
// Native SQL Query
@Query(value = "SELECT * FROM orders WHERE user_id = ?1 AND
amount > ?2",
nativeQuery = true)
List<Order> findHighValueOrders(Long userId, BigDecimal amount);
// With Named Parameters
@Query("SELECT o FROM Order o WHERE [Link] = :userId " +
"AND [Link] BETWEEN :startDate AND :endDate")
List<Order> findOrdersInPeriod(
@Param("userId") Long userId,
@Param("startDate") LocalDateTime startDate,
@Param("endDate") LocalDateTime endDate
);
// Pagination Example
@Query("SELECT o FROM Order o WHERE [Link] = ?1")
Page<Order> findUserOrdersPaginated(Long userId, Pageable
pageable);
// Custom Implementation
@Query("SELECT new map([Link] as orderId, COUNT(oi) as itemCount,
SUM([Link]) as totalQty) " +
"FROM Order o JOIN [Link] oi " +
"WHERE [Link] = ?1 " +
"GROUP BY [Link] " +
"HAVING SUM([Link]) > ?2")
List<Map<String, Object>> getOrderSummary(Long userId, Integer
minQuantity);
}
// Usage
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
public List<Order> getCompletedOrders(Long userId) {
return
[Link](us
erId, "COMPLETED");
}
public Page<Order> getUserOrdersPaginated(Long userId, int page,
int size) {
Pageable pageable = [Link](page, size, [Link]
("createdDate").descending());
return [Link](userId, pageable);
}
}

Performance & Scalability


Q18: Explain transaction management in Spring. Discuss
propagation levels.
Answer:
Transactions ensure data consistency by grouping related operations
that either all succeed or all fail.
Declarative Transaction Management:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private AuditRepository auditRepository;
@Transactional
public User createUser(User user) {
User savedUser = [Link](user);
[Link]("User created: " + [Link]());
return savedUser;
}
}
Propagation Levels:

1. REQUIRED (Default)
Use existing transaction if available, create new if not
@Transactional(propagation = [Link])
public void method() { }
2. REQUIRES_NEW
Always create new transaction, suspend existing if any
@Transactional(propagation =
Propagation.REQUIRES_NEW)
public void auditOperation() {
// Executes in separate transaction
}
3. NESTED
Create nested transaction (savepoint)
@Transactional(propagation = [Link])
public void nestedOperation() { }
4. MANDATORY
Method must execute within transaction, throws exception
otherwise
@Transactional(propagation = [Link])
public void criticalOperation() { }
5. NOT_SUPPORTED
Suspend current transaction, execute non-transactionally
@Transactional(propagation =
Propagation.NOT_SUPPORTED)
public void readOnly() { }
6. NEVER
Throw exception if transaction is active
@Transactional(propagation = [Link])
public void mustBeNonTransactional() { }
Isolation Levels:
@Transactional(isolation = [Link])
public void criticalOperation() { }
READ_UNCOMMITTED: Dirty reads allowed
READ_COMMITTED: Dirty reads prevented
REPEATABLE_READ: Dirty and non-repeatable reads prevented
SERIALIZABLE: All concurrency issues prevented (slowest)

Rollback Configuration:
@Transactional(rollbackFor = [Link], noRollbackFor =
[Link])
public void complexOperation() {
// Rolls back on any Exception except ValidationException
}

Q19: How do you optimize Spring applications? Discuss


caching strategies.
Answer:
Performance optimization involves identifying bottlenecks and
implementing efficient solutions.
Caching in Spring:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("users", "orders");
}
}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// Cache method result
@Cacheable(value = "users", key = "#id")
public User findById(Long id) {
[Link]("Fetching user from database: " + id);
return [Link](id).orElse(null);
}
// Update cache
@CachePut(value = "users", key = "#[Link]")
public User update(User user) {
return [Link](user);
}
// Invalidate cache
@CacheEvict(value = "users", key = "#id")
public void delete(Long id) {
[Link](id);
}
// Conditional caching
@Cacheable(value = "users", key = "#id",
condition = "#id > 0", unless = "#[Link]() == false")
public User findByIdConditional(Long id) {
return [Link](id).orElse(null);
}
}
Lazy Loading vs Eager Loading:
@Entity
public class User {
@Id
private Long id;
private String name;
// Lazy Loading - Loads when accessed
@OneToMany(mappedBy = "user", fetch = [Link])
private List<Order> orders;
// Eager Loading - Loads immediately
@ManyToOne(fetch = [Link])
private Department department;
}
Query Optimization:
// N+1 Query Problem - BAD
public List<User> getUsersWithOrders() {
List<User> users = [Link](); // 1 query
for (User user : users) {
[Link]().size(); // N queries
}
return users;
}
// Solution 1 - Eager Loading
@Query("SELECT DISTINCT u FROM User u LEFT JOIN FETCH
[Link]")
public List<User> getUsersWithOrdersEager();
// Solution 2 - Join Query
@Query("SELECT u FROM User u JOIN [Link] o WHERE [Link] IS NOT
NULL")
public List<User> getUsersWithOrdersJoin();
// Solution 3 - Batch Fetching
@Entity
public class User {
@OneToMany(mappedBy = "user", fetch = [Link])
@BatchSize(size = 10)
private List<Order> orders;
}

CI/CD & Deployment


Q20: Explain CI/CD pipeline with Jenkins and Docker.
Answer:
CI/CD automates building, testing, and deploying applications,
ensuring code quality and reliability.
CI/CD Pipeline Stages:

1. Source Code Management: Code pushed to Git


2. Build: Compile code, run unit tests, create artifacts
3. Test: Run integration/end-to-end tests
4. Analysis: Code quality checks (SonarQube)
5. Package: Create Docker image
6. Deploy: Deploy to staging/production
7. Monitor: Health checks, logging
Jenkins Pipeline Example:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}

stage('Build') {
steps {
sh 'mvn clean compile'
}
}

stage('Unit Tests') {
steps {
sh 'mvn test'
}
}

stage('Code Quality') {
steps {
sh 'mvn sonar:sonar -[Link]=myapp'
}
}

stage('Build Docker Image') {


steps {
script {
sh '''
docker build -t myapp:${BUILD_NUMBER} .
docker tag myapp:${BUILD_NUMBER} myapp:latest
'''
}
}
}

stage('Push to Registry') {
steps {
sh '''
docker login -u ${DOCKER_USER} -p ${DOCKER_PASS}
docker push myapp:${BUILD_NUMBER}
'''
}
}

stage('Deploy to Dev') {
steps {
sh 'kubectl apply -f k8s/dev/[Link]'
}
}

stage('Integration Tests') {
steps {
sh 'mvn verify -Pit'
}
}

stage('Deploy to Prod') {
when {
branch 'main'
}
steps {
sh 'kubectl apply -f k8s/prod/[Link]'
}
}

}
post {
always {
junit 'target/surefire-reports/*.xml'
publishHTML([
reportDir: 'target/site/jacoco',
reportFiles: '[Link]',
reportName: 'Code Coverage'
])
}
}
}
Dockerfile:
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/[Link] [Link]
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "[Link]"]
Kubernetes Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-Xmx512m"
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10

Additional Advanced Topics


Q21: Explain microservices architecture. How do you
handle service-to-service communication?
Answer:
Microservices break applications into small, independent services,
each with specific business capability.
Synchronous Communication (REST):
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
public Order createOrder(OrderRequest request) {
Order order = new Order();
[Link]([Link]());

// Call User Service


User user = [Link](
"[Link] + [Link](),
[Link]
);

if (user == null) {
throw new UserNotFoundException();
}

return [Link](order);

}
}
Asynchronous Communication (Message Queue):
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void createOrder(Order order) {
[Link](order);

// Send message to queue


[Link]("[Link]", "[Link]",
new OrderCreatedEvent([Link](), [Link]()));

}
}
@Component
public class OrderEventListener {
@RabbitListener(queues = "[Link]")
public void handleOrderCreated(OrderCreatedEvent event) {
[Link]("Order created: " + [Link]());
// Trigger email notification, update analytics, etc.
}
}
Service Discovery:
@Configuration
public class ServiceRegistry {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.interceptors((request, body, execution) -> {
// Add service discovery logic
return [Link](request, body);
})
.build();
}
}
Service-to-Service Authentication:
@Component
public class ServiceAuthenticator {
public String getServiceToken() {
// OAuth2 token exchange
return [Link]();
}
}

Q22: Explain the N+1 query problem and solutions.


Answer:
N+1 problem occurs when accessing related entities triggers
additional queries.
Problem Example:
// BAD - Causes N+1 queries
public List<User> getUsersWithOrders() {
List<User> users = [Link](); // 1 query
for (User user : users) {
[Link]([Link]()); // N additional queries
}
return users;
}
// Results in: 1 query (users) + N queries (for each user's orders)
Solution 1: JPQL Join Fetch
@Query("SELECT DISTINCT u FROM User u LEFT JOIN FETCH
[Link]")
public List<User> findAllWithOrdersEager();
// Usage - Only 1 query
List<User> users = [Link]();
Solution 2: Named Entity Graph
@NamedEntityGraph(name = "[Link]",
attributeNodes = @NamedAttributeNode("orders"))
@Entity
public class User { }
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@EntityGraph("[Link]")
List<User> findAll();
}
Solution 3: Batch Fetching
@Entity
public class User {
@OneToMany(mappedBy = "user", fetch = [Link])
@BatchSize(size = 20)
private List<Order> orders;
}
// Results in: 1 query (users) + 1 query per 20 users (batched orders)
Solution 4: DTO Projection
public interface UserOrderDTO {
Long getId();
String getName();
List<Order> getOrders();
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u JOIN FETCH [Link] WHERE
[Link] = 'ACTIVE'")
List<UserOrderDTO> findActiveUsersWithOrders();
}
Q23: What is the SOLID principle? Apply to Java design.
Answer:
SOLID principles promote maintainable, scalable, and robust
software design.
S - Single Responsibility Principle
// BAD - Multiple responsibilities
public class User {
public void save(User user) { /* DB logic / }
public void sendEmail(String email) { / Email logic / }
public void generateReport() { / Report logic */ }
}
// GOOD - Single responsibility
public class User {
private String email;
private String name;
}
public class UserRepository {
public void save(User user) { /* DB logic */ }
}
public class EmailService {
public void sendEmail(String email) { /* Email logic */ }
}
public class ReportGenerator {
public void generateReport() { /* Report logic */ }
}
O - Open/Closed Principle
// BAD - Closed for extension
public class PaymentProcessor {
public void process(String type, double amount) {
if ("CREDIT_CARD".equals(type)) {
// Credit card logic
} else if ("UPI".equals(type)) {
// UPI logic
}
}
}
// GOOD - Open for extension
public interface PaymentMethod {
void process(double amount);
}
public class CreditCardPayment implements PaymentMethod {
public void process(double amount) { }
}
public class UPIPayment implements PaymentMethod {
public void process(double amount) { }
}
public class PaymentProcessor {
private PaymentMethod paymentMethod;
public void process(double amount) {
[Link](amount);
}
}
L - Liskov Substitution Principle
// BAD - Rectangle and Square violation
public class Rectangle {
protected int width, height;
public void setWidth(int w) { [Link] = w; }
public void setHeight(int h) { [Link] = h; }
}
public class Square extends Rectangle {
@Override
public void setWidth(int w) {
[Link] = w;
[Link] = w; // Forces equal sides
}
}
// Problem: Square violates Rectangle contract
// GOOD - Proper hierarchy
public interface Shape {
int getArea();
}
public class Rectangle implements Shape {
private int width, height;
public Rectangle(int width, int height) {
[Link] = width;
[Link] = height;
}
public int getArea() { return width * height; }
}
public class Square implements Shape {
private int side;
public Square(int side) { [Link] = side; }
public int getArea() { return side * side; }
}
I - Interface Segregation Principle
// BAD - Fat interface
public interface Worker {
void work();
void eat();
void sleep();
}
public class Robot implements Worker {
public void work() { }
public void eat() { } // Irrelevant for robot
public void sleep() { } // Irrelevant for robot
}
// GOOD - Segregated interfaces
public interface Worker {
void work();
}
public interface Eater {
void eat();
}
public interface Sleeper {
void sleep();
}
public class Human implements Worker, Eater, Sleeper {
public void work() { }
public void eat() { }
public void sleep() { }
}
public class Robot implements Worker {
public void work() { }
}
D - Dependency Inversion Principle
// BAD - High-level depends on low-level
public class UserService {
private MySQLDatabase database = new MySQLDatabase();
public void saveUser(User user) {
[Link](user);
}
}
// GOOD - Both depend on abstraction
public interface Database {
void save(User user);
}
public class MySQLDatabase implements Database {
public void save(User user) { }
}
public class UserService {
private Database database;
public UserService(Database database) {
[Link] = database;
}
public void saveUser(User user) {
[Link](user);
}
}

Q24: Explain thread safety in Java. How do you make


collections thread-safe?
Answer:
Thread safety ensures that shared data is accessed correctly by
multiple threads.
Synchronization Approaches:

1. Synchronized Methods
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
2. Synchronized Blocks
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
}
3. AtomicInteger
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
[Link]();
}
public int getCount() {
return [Link]();
}
}
4. Thread-Safe Collections
// [Link]
Map<String, String> map = [Link](new
HashMap<>());
// ConcurrentHashMap (better for high concurrency)
Map<String, String> concurrentMap = new ConcurrentHashMap<>();
// CopyOnWriteArrayList
List<String> list = new CopyOnWriteArrayList<>();
// BlockingQueue
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
5. ReentrantLock
public class Counter {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
[Link]();
try {
count++;
} finally {
[Link]();
}
}
}
6. ReadWriteLock
public class Cache {
private Map<String, Object> cache = new HashMap<>();
private final ReadWriteLock lock = new
ReentrantReadWriteLock();
public Object get(String key) {
[Link]().lock();
try {
return [Link](key);
} finally {
[Link]().unlock();
}
}
public void put(String key, Object value) {
[Link]().lock();
try {
[Link](key, value);
} finally {
[Link]().unlock();
}
}
}

Q25: Explain RESTful API design principles and best


practices.
Answer:
REST (Representational State Transfer) provides guidelines for
building scalable, stateless web services.
Core Principles:

1. Resources: Everything is a resource (users, orders, products)


2. Representations: JSON/XML represent resource states
3. Statelessness: Each request contains all needed information
4. HTTP Methods: Use appropriate verbs
Best Practices:

1. Resource URIs (Nouns, not verbs)


✓ GET /api/users
✓ GET /api/users/123
✓ POST /api/users
✗ GET /api/getUsers
✗ POST /api/createUser
2. HTTP Status Codes
200 OK - Successful GET, PUT, PATCH
201 Created - Successful POST
204 No Content - Successful DELETE
400 Bad Request - Invalid input
401 Unauthorized - Authentication needed
403 Forbidden - Not permitted
404 Not Found - Resource doesn't exist
500 Internal Server Error - Server error
3. Spring REST Controller Example
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// GET all users with pagination
@GetMapping
public Page<UserDTO> getAllUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return [Link](page, size);
}
// GET single user
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUserById(@PathVariable Long
id) {
UserDTO user = [Link](id);
return [Link](user);
}
// POST create user
@PostMapping
public ResponseEntity<UserDTO> createUser(@Valid @RequestBody
CreateUserRequest request) {
UserDTO user = [Link](request);
return [Link]([Link]).body(user);
}
// PUT update user
@PutMapping("/{id}")
public ResponseEntity<UserDTO> updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
UserDTO user = [Link](id, request);
return [Link](user);
}
// PATCH partial update
@PatchMapping("/{id}")
public ResponseEntity<UserDTO> partialUpdate(
@PathVariable Long id,
@RequestBody Map<String, Object> updates) {
UserDTO user = [Link](id, updates);
return [Link](user);
}
// DELETE user
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
[Link](id);
return [Link]().build();
}
}
4. Versioning Strategy
// URL Versioning
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 { }
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 { }
// Header Versioning
@RestController
@RequestMapping("/api/users")
@GetMapping(headers = "API-Version=1")
public List<UserDTOV1> getUsersV1() { }
@GetMapping(headers = "API-Version=2")
public List<UserDTOV2> getUsersV2() { }
5. Error Handling
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse> handleUserNotFound(
UserNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"USER_NOT_FOUND",
[Link](),
[Link]()
);
return [Link](HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse> handleValidationError(
MethodArgumentNotValidException ex) {
String message = [Link]()
.getFieldErrors()
.stream()
.map(f -> [Link]() + ": " + [Link]())
.collect([Link](", "));

ErrorResponse error = new ErrorResponse(


"VALIDATION_ERROR",
message,
[Link]()
);
return [Link](HttpStatus.BAD_REQUEST).body(error);
}
}

Q26-50: Additional Core Questions (Continued)


[Due to length constraints, here are the remaining topics with brief
outlines]
Q26: Explain the difference between ArrayList and LinkedList. When
to use each?
ArrayList: Backed by array, fast random access, slow
insertion/deletion
LinkedList: Doubly-linked list, slow random access, fast
insertion/deletion
Q27: What are garbage collection algorithms in Java?

Mark and Sweep, Mark and Compact, Copying, Generational GC


Q28: Explain volatile keyword and memory visibility in Java.

Ensures visibility across threads, prevents caching in registers


Q29: What is the difference between equals() and hashCode()?

equals(): Compares object content; hashCode(): Returns hash


value for HashMap/Set
Q30: Explain immutability in Java. How do you create immutable
objects?
Final class, final fields, defensive copying, private constructor
Q31: What is the difference between pass-by-value and pass-by-
reference?
Java is pass-by-value; object references are passed by value
Q32: Explain exception hierarchy. How would you create custom
exceptions?
Extend Exception or RuntimeException class
Q33: What is composition over inheritance? Provide examples.

Prefer object composition to inheritance for flexibility


Q34: Explain the Builder pattern in practice.

Construct complex objects step by step with fluent API


Q35: What is the Decorator pattern? Provide Java I/O examples.

BufferedInputStream decorates InputStream for buffering


Q36: Explain the Template Method pattern.

Define algorithm skeleton in superclass, let subclasses override


steps
Q37: What is the Command pattern? Real-world use cases.

Encapsulate requests as objects, enable queuing/undo


Q38: Explain the Chain of Responsibility pattern.

Pass request along chain of handlers until one handles it


Q39: What is the Proxy pattern? When would you use it?

Provide placeholder/surrogate for another object


Q40: Explain Stream API advantages over traditional iteration.

Declarative, functional, enables parallel processing


Q41: What is the difference between flatMap() and map()?

map(): Transform each element; flatMap(): Transform and


flatten
Q42: How do you handle optional values in Java 8+?

Use [Link](), [Link](), [Link]()


Q43: What is StringBuffer vs StringBuilder?
StringBuffer: Synchronized (thread-safe); StringBuilder: Not
synchronized
Q44: Explain String interning and string pool.

Intern string literals in memory pool for memory efficiency


Q45: What are the differences between interface and abstract class in
Java 8+?
Interfaces: Multiple default methods; Abstract class: Single
inheritance
Q46: Explain marker interfaces and their purpose.

Serializable, Cloneable - Signal capability to JVM


Q47: What is method overloading vs method overriding?

Overload: Same name, different parameters; Override: Same


signature in subclass
Q48: Explain the Comparator vs Comparable interface.

Comparable: Within class; Comparator: External comparison


logic
Q49: What is the difference between [Link]() and
[Link]()?
Arrays: For arrays; Collections: For collections
Q50: How would you approach debugging a memory leak in Java?

Use profilers, check long-lived object references, analyze heap


dumps

References
[1] Oracle. (2024). Java Language and Virtual Machine Specifications.
[Link]
[2] Spring Project. (2024). Spring Framework Documentation. [Link]
[Link]/projects/spring-framework
[3] Baeldung. (2024). Spring Interview Questions. [Link]
[Link]/spring-interview-questions
[4] Gang of Four. (1994). Design Patterns: Elements of Reusable Object-
Oriented Software. Addison-Wesley.
[5] Martin, R. C. (2008). Clean Code: A Handbook of Agile Software
Craftsmanship. Prentice Hall.

Document prepared: February 2026


Target Position: Senior Java Developer
Experience Level: 5+ Years with Java/Spring

Good luck with your interview! Remember to provide real examples


from your experience and discuss your problem-solving approach.

You might also like