Skip to content

Java Backend Developer Interview Questions & Answers

40 questions for Java Backend Developer interviews — 7 easy, 28 medium, 5 hard.

About the Java Backend Developer role

A Java backend developer designs and builds REST APIs and business logic with Spring Boot, JPA and relational databases. The role involves writing clean, tested code, tuning queries, handling transactions and integrating with other services. It is in strong demand at fintechs, ecommerce firms and banks, which expect solid Java, Spring and SQL skills plus an understanding of performance and reliability.

Spring Boot REST APIs JPA and Hibernate SQL tuning JUnit and Mockito
Solved for this roleStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What is the difference between Collectors.toMap() and groupingBy()?

Save to ▾
Show answer
toMap() creates one entry per element using key and value functions and throws IllegalStateException on duplicate keys unless you give a merge function. groupingBy() collects all elements with the same key into a List by default, or applies a downstream collector like counting or summingInt. Use toMap for unique keys like id and groupingBy for categories like city.
02

Bind typed configuration properties with validation in Spring Boot.

Save to ▾
Show answer
Use a record with @ConfigurationProperties. @ConfigurationProperties(prefix = "payment") @Validated public record PaymentProps( @NotBlank String baseUrl, @Min(100) int timeoutMs) {} // application.yml // payment: // base-url: https://pay.internal // timeout-ms: 2000 Enable it with @ConfigurationPropertiesScan on the main class. The app fails at startup if values are invalid.
03

How does Spring Boot auto-configuration work?

Save to ▾
Show answer
At startup Spring Boot reads auto-configuration classes listed in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. Each class uses conditions like @ConditionalOnClass, @ConditionalOnMissingBean and @ConditionalOnProperty, so it creates beans only when the library is on the classpath and you have not defined your own. Run with --debug to see the condition report showing what was applied and why.
04

An API listing 100 orders fires 101 SQL queries. How do you fix it?

Save to ▾
Show answer
This is the N+1 problem from a lazy association loaded in a loop or by JSON serialisation. Fetch what the endpoint needs in one query with JOIN FETCH or @EntityGraph(attributePaths = "items"), or use a DTO projection query. For collections with pagination, fetch ids first, then fetch associations in a second query to avoid in-memory paging. Add a test that asserts the query count.
05

A query is fast in development but takes 8 seconds in production. How do you investigate?

Save to ▾
Show answer
Production has more data, so check the execution plan with EXPLAIN ANALYZE on production-like data. Look for full table scans, missing indexes on filter or join columns, functions on indexed columns and poor statistics. Check if Hibernate generates the SQL you expect. Add a suitable composite index, rewrite the query or paginate, and verify the plan improves before release.
06

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

Save to ▾
Show answer
map() transforms each element into exactly one new element, so a Stream of orders mapped to totals stays one-to-one. flatMap() transforms each element into a stream and flattens all of them into one stream, which is useful for one-to-many cases, such as turning a list of orders into a single stream of all items with orders.stream().flatMap(o -> o.items().stream()).
07

What is the N+1 select problem in Hibernate and how do you fix it?

Save to ▾
Show answer
N+1 happens when you load N parent entities with one query and then a lazy association triggers one extra query per parent, giving N+1 queries. Fix it with a JOIN FETCH in JPQL, an @EntityGraph on the repository method, or batch fetching with @BatchSize or hibernate.default_batch_fetch_size. Detect it by enabling SQL logging or using a query count assertion in tests.
08

Write a unit test for a service class using JUnit 5 and Mockito.

Save to ▾
Show answer
Mock the repository and verify behaviour. @ExtendWith(MockitoExtension.class) class ProductServiceTest { @Mock ProductRepository repo; @InjectMocks ProductService service; @Test void throwsWhenMissing() { when(repo.findById(1L)).thenReturn(Optional.empty()); assertThrows(NotFoundException.class, () -> service.get(1L)); verify(repo).findById(1L); } } No Spring context starts, so the test runs in milliseconds.
09

What is the difference between JPA, Hibernate and Spring Data JPA?

Save to ▾
Show answer
JPA, now Jakarta Persistence, is a specification of interfaces and annotations for object relational mapping. Hibernate is the most popular implementation of that specification and adds its own features. Spring Data JPA sits on top and generates repository implementations from interfaces and method names like findByEmail, reducing boilerplate. Your code uses JPA annotations, Hibernate does the work and Spring Data simplifies access.
10

You need to process a 5 GB file using streams without running out of memory. How?

Save to ▾
Show answer
Use Files.lines(path), which reads lazily line by line, inside try-with-resources. Apply filter and map, then aggregate with a collector that keeps small results such as counts or sums instead of collecting all lines into a list. If the output is large, write it incrementally to a BufferedWriter. Avoid sorted() and distinct() on huge data because they buffer everything.
11

What is Spring Boot and how is it different from the Spring Framework?

Save to ▾
Show answer
Spring Framework provides dependency injection, MVC, transactions and data access but needs manual configuration. Spring Boot builds on it with auto-configuration, starter dependencies, an embedded server such as Tomcat and production features through Actuator, so you can run a service with java -jar. Spring Boot 3 requires Java 17 or later and uses Jakarta EE packages instead of javax.
12

Explain the entity lifecycle states in JPA.

Save to ▾
Show answer
Transient: a new object not yet linked to a persistence context. Managed (persistent): attached to the context, so changes are tracked and flushed automatically through dirty checking. Detached: was managed but the context closed or it was evicted; changes are not tracked until merge(). Removed: scheduled for deletion on flush. persist, merge, detach and remove move entities between these states.
13

How do you explain OOP concepts to a junior developer who is new to Java?

Save to ▾
Show answer
Situation: I mentored two interns who struggled with OOP. Task: help them design classes for a library app. Action: I used real objects they knew, like Book and Member, showed encapsulation with private fields, then wrote one interface with two implementations to show polymorphism, and reviewed their code daily. Result: within two weeks they designed modules on their own and their pull requests needed fewer review comments.
14

A batch job inserting 1 lakh rows through JPA takes 30 minutes. How do you speed it up?

Save to ▾
Show answer
Enable JDBC batching with hibernate.jdbc.batch_size around 50 and order_inserts, and avoid IDENTITY id generation, which disables insert batching; use a SEQUENCE with a pooled optimizer. Flush and clear the EntityManager every batch so the persistence context does not grow. For very large loads use JdbcTemplate batchUpdate or the database bulk loader. This often cuts time to a minute or two.
15

How do you handle a situation where you made a wrong technical decision?

Save to ▾
Show answer
Situation: I chose eager loading for a reporting entity to save time, and later pages became slow. Task: own and fix it. Action: I told my lead, measured the impact, switched associations to lazy with targeted fetch joins and added query count tests. Result: performance recovered within a sprint and I now review fetch strategy in every design discussion.
16

Tell me about a time you made a codebase more readable.

Save to ▾
Show answer
Situation: our reporting module had nested loops 200 lines long that new joiners feared. Task: make it maintainable without changing output. Action: I added snapshot tests on real report files, then refactored into small methods using streams, groupingBy and records for intermediate data, and reviewed each step with a teammate. Result: the module shrank by 40 percent and later changes took a day instead of a week.
17

Write a stream to partition numbers into even and odd lists.

Save to ▾
Show answer
partitioningBy splits into a map with true and false keys. Map<Boolean, List<Integer>> parts = nums.stream() .collect(Collectors.partitioningBy(n -> n % 2 == 0)); List<Integer> evens = parts.get(true); List<Integer> odds = parts.get(false); Both keys are always present, even if one list is empty, unlike groupingBy.
18

Your Spring Boot service takes 40 seconds to start in Kubernetes and pods get killed. How do you fix it?

Save to ▾
Show answer
First set a startupProbe so Kubernetes waits for startup before liveness checks begin. Then reduce start time: remove unused starters, enable lazy initialisation where safe, avoid heavy work in @PostConstruct, give enough CPU at start and consider AppCDS. For very fast startup, a GraalVM native image built with Spring AOT can start in under a second, with some trade-offs.
19

Using streams, find the employee with the highest salary in each department.

Save to ▾
Show answer
Group by department with a maxBy downstream collector. Map<String, Optional<Employee>> top = employees.stream() .collect(Collectors.groupingBy( Employee::department, Collectors.maxBy(Comparator.comparingInt(Employee::salary)))); To get values without Optional, wrap with collectingAndThen(maxBy(...), Optional::get), which is safe because each group has at least one element.
20

Why is PreparedStatement preferred over Statement?

Save to ▾
Show answer
PreparedStatement sends the SQL with placeholders separately from the parameter values, so user input is never treated as SQL, which prevents SQL injection. The database can also cache and reuse the execution plan, and it handles types like dates correctly. Statement with string concatenation is unsafe and slower for repeated queries, so it should not be used with user input.
21

Write a minimal Dockerfile for a Spring Boot application.

Save to ▾
Show answer
A multi-stage build keeps the image small. FROM eclipse-temurin:21-jdk AS build WORKDIR /app COPY . . RUN ./mvnw -q package -DskipTests FROM eclipse-temurin:21-jre WORKDIR /app COPY --from=build /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75", "-jar", "app.jar"] Spring Boot can also build images without a Dockerfile using mvn spring-boot:build-image.
22

Users get LazyInitializationException when the API returns an entity. What is happening?

Save to ▾
Show answer
The entity was loaded inside a transaction, the session closed, and then Jackson touched a lazy association outside it. Do not fix it by turning on open-session-in-view or making everything eager. Instead, map the entity to a DTO inside the service transaction and fetch needed associations explicitly with JOIN FETCH or an entity graph. Spring Boot logs a warning because open-in-view is on by default.
23

What is the difference between lazy and eager loading?

Save to ▾
Show answer
Lazy loading fetches an association only when it is first accessed, using a proxy; eager loading fetches it immediately with the parent. In JPA, @ManyToOne and @OneToOne default to EAGER, while @OneToMany and @ManyToMany default to LAZY. Best practice is to make all associations lazy and fetch what each use case needs with JOIN FETCH or entity graphs, which avoids loading huge object graphs.
24

Write a JDBC batch insert for a list of products.

Save to ▾
Show answer
Batching sends many rows in one round trip. String sql = "INSERT INTO product(name, price) VALUES (?, ?)"; try (Connection c = ds.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) { c.setAutoCommit(false); int n = 0; for (Product p : products) { ps.setString(1, p.name()); ps.setLong(2, p.price()); ps.addBatch(); if (++n % 500 == 0) ps.executeBatch(); } ps.executeBatch(); c.commit(); }
25

You must expose configuration that differs between dev, QA and production. How do you manage it?

Save to ▾
Show answer
Use Spring profiles with application-dev.yml and application-prod.yml, and bind settings to typed @ConfigurationProperties classes with validation. Keep secrets out of the repo by injecting them through environment variables, Kubernetes Secrets or a vault. Activate the profile with SPRING_PROFILES_ACTIVE in each environment. Use the same build artefact everywhere and change only configuration.
26

Legacy code uses anonymous classes and loops everywhere. How would you modernise it safely?

Save to ▾
Show answer
First add tests around the behaviour. Then refactor in small steps: anonymous Comparators and Runnables become lambdas, simple loops that filter and transform become streams, and null checks around returns become Optional where useful. Keep complex loops with early exits as loops if a stream is less readable. Use IDE refactorings and review each change to avoid altering behaviour.
27

toMap() throws Duplicate key exception in production. How do you fix it?

Save to ▾
Show answer
The data has repeated keys that the developer assumed were unique. Decide the business rule, then pass a merge function, for example toMap(User::email, u -> u, (a, b) -> a) to keep the first, or use groupingBy if all values are needed. Also check upstream data quality, since duplicates may signal a deeper bug such as missing unique constraints.
28

A stream pipeline that updates a shared ArrayList in forEach gives random results with parallel(). Why?

Save to ▾
Show answer
ArrayList is not thread safe, and parallel streams run forEach on many threads, so additions race, get lost or throw exceptions. Side effects in streams are the problem. Replace forEach with collect(Collectors.toList()) or toList(), which handles merging per thread safely. Keep lambdas stateless and avoid modifying external state inside stream operations.
29

What is the difference between reduce() and collect()?

Save to ▾
Show answer
reduce() combines elements into a single immutable value using an identity and an associative function, such as summing numbers. collect() is a mutable reduction that accumulates into a container like a List, Map or StringBuilder, which is far more efficient for building collections. Using reduce to build a list creates many intermediate copies, so use collect for containers.
30

Explain bean scopes in Spring.

Save to ▾
Show answer
singleton is the default: one instance per application context. prototype creates a new instance each time it is requested. Web scopes include request, session and application. Singletons must be stateless or thread safe because all requests share them. Injecting a prototype into a singleton gives only one instance, so use ObjectProvider or a scoped proxy to get fresh ones.
31

A @Transactional method is not rolling back after an exception. What could be wrong?

Save to ▾
Show answer
Check that the exception is unchecked, since checked exceptions do not roll back unless rollbackFor is set. Check that the method is called through the Spring proxy, not from another method in the same class. Make sure the method is public and the exception is not caught and swallowed inside. Also confirm the database engine supports transactions and the right transaction manager is used.
32

Write a Kafka producer and consumer in Spring Boot.

Save to ▾
Show answer
Spring Kafka hides most boilerplate. @Service class OrderEvents { private final KafkaTemplate<String, OrderPlaced> kafka; OrderEvents(KafkaTemplate<String, OrderPlaced> k) { kafka = k; } void publish(OrderPlaced e) { kafka.send("orders", e.orderId(), e); } } @Component class OrderListener { @KafkaListener(topics = "orders", groupId = "inventory") void on(OrderPlaced e) { inventory.reserve(e); } } Using orderId as key keeps events for one order in the same partition and order.
33

Map a one-to-many relation between Order and OrderItem in JPA.

Save to ▾
Show answer
Make the child own the foreign key and keep both sides in sync. @Entity class Order { @Id @GeneratedValue Long id; @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) List<OrderItem> items = new ArrayList<>(); void addItem(OrderItem i) { items.add(i); i.setOrder(this); } } @Entity class OrderItem { @Id @GeneratedValue Long id; @ManyToOne(fetch = FetchType.LAZY) Order order; }
34

What is Spring Boot Actuator used for?

Save to ▾
Show answer
Actuator adds production endpoints such as /actuator/health for liveness and readiness probes, /actuator/metrics and /actuator/prometheus for Micrometer metrics, plus info, loggers and thread dumps. Expose only what you need with management.endpoints.web.exposure.include and secure sensitive endpoints with Spring Security. Kubernetes uses the health groups to decide restarts and traffic routing.
35

What does effectively final mean for lambdas?

Save to ▾
Show answer
A lambda can use a local variable from the enclosing method only if that variable is final or effectively final, meaning it is never reassigned after initialisation. Lambdas capture the value, not the variable, so this avoids confusing behaviour and races. To accumulate results, use a stream collector or an AtomicInteger instead of changing a captured local.
36

Tell me about a time you found and fixed a difficult production bug in a Java application.

Save to ▾
Show answer
Situation: our order service crashed with OutOfMemoryError every few days. Task: find the root cause without long downtime. Action: I enabled heap dumps on OOM, analysed the dump in Eclipse MAT and found a static HashMap used as a cache that was never cleared. I replaced it with a bounded Caffeine cache with expiry and added a heap usage alert. Result: no crashes in six months and memory stayed flat.
37

Write a Spring Data JPA repository method that fetches orders with items to avoid N+1.

Save to ▾
Show answer
Use JOIN FETCH or an entity graph. public interface OrderRepository extends JpaRepository<Order, Long> { @Query("select distinct o from Order o join fetch o.items where o.customerId = :cid") List<Order> findWithItems(@Param("cid") Long customerId); @EntityGraph(attributePaths = "items") List<Order> findByStatus(String status); } Both load orders and items in one query.
38

Write a sealed interface with records and a switch that computes area.

Save to ▾
Show answer
The switch needs no default because the type set is closed. sealed interface Shape permits Circle, Rect {} record Circle(double r) implements Shape {} record Rect(double w, double h) implements Shape {} static double area(Shape s) { return switch (s) { case Circle c -> Math.PI * c.r() * c.r(); case Rect(double w, double h) -> w * h; }; }
39

Flatten a list of lists of integers and compute the sum of squares of the even numbers.

Save to ▾
Show answer
flatMap then use a primitive stream to avoid boxing. int result = lists.stream() .flatMap(List::stream) .filter(n -> n % 2 == 0) .mapToInt(n -> n * n) .sum(); mapToInt returns an IntStream, whose sum() is simpler and faster than reduce on boxed Integers.
40

Clients report duplicate orders when they retry after a timeout. How do you prevent it?

Save to ▾
Show answer
Make the create order API idempotent. The client sends an Idempotency-Key header; the server stores the key with the result in a table with a unique constraint or in Redis. A retry with the same key returns the saved response instead of creating a new order. Database unique constraints on business keys add another safety net.

Frequently asked questions

What does a Java Backend Developer do?

A Java backend developer designs and builds REST APIs and business logic with Spring Boot, JPA and relational databases. The role involves writing clean, tested code, tuning queries, handling transactions and integrating with other services. It is in strong demand at fintechs, ecommerce firms and banks, which expect solid Java, Spring and SQL skills plus an understanding of performance and reliability.

Which skills are tested in a Java Backend Developer interview?

Expect questions on Spring Boot, REST APIs, JPA and Hibernate, SQL tuning, JUnit and Mockito. Most rounds also ask you to explain a project and solve one practical problem live.

How do I prepare for a Java Backend Developer interview?

Revise Spring Boot and Microservices, JDBC, Hibernate and JPA, Java 8+ Features and Streams first using the topic sheets, practise the questions on this page aloud, then do one full mock interview to practise timing.