Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.
About SAP hiring for Java roles
SAP is a German enterprise software company known for ERP systems like SAP S/4HANA, along with analytics, cloud and business AI products. SAP Labs India in Bengaluru and Gurugram is one of its largest development centres. It hires for software developers, quality engineers, data engineers and analytics roles.
For Java roles, this SAP practice set focuses most on Multithreading and Concurrency (7), Java 8+ Features and Streams (6), Strings and Exception Handling (5), OOP in Java (4). It has 19 medium, 11 hard questions, so you can start easy and work up to the harder ones.
Company type
Product
Headquarters
Walldorf, Germany
Main India offices
Bengaluru, Gurugram, Pune, Mumbai
SAP Java interview process
Online assessment (aptitude + coding)
Technical round 1
Technical round 2
Managerial round
HR round
Typical pattern based on public candidate experiences. Rounds vary by role, team and year.
Solved for SAPStart 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
Legacy code uses anonymous classes and loops everywhere. How would you modernise it safely?
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.
02
Write code that runs 10,000 blocking tasks using virtual threads.
Use the virtual-thread-per-task executor in Java 21.
try (var ex = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
int id = i;
ex.submit(() -> {
Thread.sleep(Duration.ofMillis(200));
return id;
});
}
} // close() waits for all tasks
All tasks finish in about 200 ms because blocked virtual threads free their carriers.
03
Write a record with validation in its compact constructor.
A compact constructor runs before fields are assigned.
public record Money(String currency, long paise) {
public Money {
Objects.requireNonNull(currency);
if (paise < 0) {
throw new IllegalArgumentException("negative amount");
}
}
public Money add(Money o) {
return new Money(currency, paise + o.paise);
}
}
Storing money in paise as long avoids floating point errors.
04
You need to process a 5 GB file using streams without running out of memory. How?
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.
A deadlock happens when two or more threads each hold a lock and wait for a lock held by the other, so none can continue. It needs mutual exclusion, hold and wait, no preemption and circular wait. Prevent it by always acquiring locks in the same global order, using tryLock with a timeout, holding locks briefly and avoiding calls to unknown code while holding a lock.
06
What is CompletableFuture and how is it better than Future?
Future only lets you block with get() to obtain a result. CompletableFuture supports non-blocking composition: thenApply to transform, thenCompose to chain async calls, thenCombine or allOf to join several, and exceptionally or handle for errors. It runs on the common ForkJoinPool by default, but pass your own executor for blocking I/O to avoid starving the pool.
07
Run two tasks in parallel with CompletableFuture and combine their results.
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
How do you take a thread dump and a heap dump of a running Java process?
Find the process id with jps or ps, then use jcmd, which is the recommended tool.
jps -l
jcmd <pid> Thread.print > threads.txt
jcmd <pid> GC.heap_dump /tmp/heap.hprof
Older tools jstack and jmap do the same. Take three thread dumps a few seconds apart to spot stuck threads, and analyse heap dumps in Eclipse MAT.
10
A file handle leak causes Too many open files errors after a day. What is the likely cause?
Streams, readers or connections are opened but not closed on all paths, especially when an exception is thrown before close(). Check with lsof or jcmd which files are open. Fix by wrapping every resource in try-with-resources so it always closes, and make sure Files.lines() and Files.list() streams are closed too, since they hold file handles.
11
Write a minimal Dockerfile for a Spring Boot application.
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.
12
What are virtual threads and when should you use them?
Virtual threads, final in Java 21, are lightweight threads managed by the JVM and mounted on a small pool of carrier OS threads. When one blocks on I/O, it unmounts so the carrier can run another. You can run millions of them, which suits thread-per-request servers doing lots of blocking calls. They do not speed up CPU-bound work, and you should not pool them.
13
A batch job inserting 1 lakh rows through JPA takes 30 minutes. How do you speed it up?
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.
14
A stream pipeline that updates a shared ArrayList in forEach gives random results with parallel(). Why?
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.
15
How does JWT based authentication work in a Spring Boot API?
After login, the auth server issues a signed JWT with claims like user id, roles and expiry. The client sends it in the Authorization: Bearer header. The API, configured as an OAuth2 resource server in Spring Security, verifies the signature with the public key, checks expiry and builds the security context, so no session is needed. Keep tokens short-lived and use refresh tokens for renewal.
16
What are records in Java and when should you use them?
Records, final in Java 16, are concise classes for immutable data. record Point(int x, int y) {} generates private final fields, a canonical constructor, accessors, equals(), hashCode() and toString(). You can add validation in a compact constructor and add methods. Use them for DTOs, API responses and map keys. They cannot extend another class and are not suited to JPA entities, which need mutability.
17
Tell me about a time you made a codebase more readable.
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.
18
Exceptions are being swallowed with empty catch blocks in your codebase. How would you fix this?
Empty catches hide failures and make production issues invisible. I would find them with static analysis like SonarQube, then decide per case: handle the error properly, rethrow wrapped with context, or at least log with the stack trace. I would add a global exception handler for APIs and a team rule in code review and lint config to block new empty catch blocks.
A token bucket with synchronized refill is simple and correct.
class RateLimiter {
private final long capacity, refillPerSec;
private double tokens; private long last = System.nanoTime();
RateLimiter(long cap, long rps) { capacity = cap; refillPerSec = rps; tokens = cap; }
synchronized boolean tryAcquire() {
long now = System.nanoTime();
tokens = Math.min(capacity, tokens + (now - last) / 1e9 * refillPerSec);
last = now;
if (tokens >= 1) { tokens--; return true; }
return false;
}
}
Across servers, keep the bucket in Redis.
21
A stream over a list of orders is slow in a hot path. How do you analyse it?
Profile first with JFR or async-profiler to confirm the stream is the hotspot. Check for repeated work like calling sorted() inside a loop, boxing overhead with Stream of Integer instead of IntStream, or re-streaming the same list many times. Cache computed maps, use primitive streams and, if still slow, a plain loop can be clearer and faster for very hot code.
22
A log file shows a NullPointerException only for some users. How do you debug it?
Start with the stack trace; since Java 14 helpful NPE messages name exactly which variable was null. Reproduce with the failing user's data, which often has an optional field missing. Fix the root cause by validating input at the boundary, using Optional for values that may be absent and annotating with @NonNull. Add a unit test for that data case so it does not return.
23
Write a custom unchecked exception and a Spring handler that returns HTTP 404.
Define the exception, then map it centrally.
public class NotFoundException extends RuntimeException {
public NotFoundException(String msg) { super(msg); }
}
@RestControllerAdvice
public class ApiErrors {
@ExceptionHandler(NotFoundException.class)
public ProblemDetail notFound(NotFoundException e) {
return ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND, e.getMessage());
}
}
24
Group a list of orders by city and sum the amount per city.
Use groupingBy with a summing collector.
Map<String, Double> totals = orders.stream()
.collect(Collectors.groupingBy(
Order::city,
TreeMap::new,
Collectors.summingDouble(Order::amount)));
TreeMap keeps cities sorted. For money, store amounts as long paise or BigDecimal and use Collectors.reducing with BigDecimal::add.
finally runs after try and catch in almost every case, including when the try block returns or throws. It does not run if the JVM exits through System.exit(), the process is killed or the thread dies abruptly. Avoid returning from finally, because that silently overrides the try block's return value and swallows exceptions.
26
A downstream payment service is slow and your API threads pile up. How do you protect your service?
Set strict connect and read timeouts on the HTTP client. Add a Resilience4j circuit breaker so calls fail fast once the error rate crosses a threshold, a bulkhead to limit concurrent calls and retry with backoff only for safe idempotent requests. Return a clear fallback such as payment pending. Monitor breaker state through Actuator metrics and alerts.
27
What is the Liskov Substitution Principle? Give an example of breaking it.
LSP says any subclass object must be usable wherever the parent is expected without breaking behaviour. A classic violation is Square extends Rectangle: setting width also changes height, so code that sets width 5 and height 4 and expects area 20 fails. Another is a subclass throwing UnsupportedOperationException for a parent method. The fix is a better hierarchy or composition.
28
Tell me about a time you solved a concurrency bug.
Situation: our wallet service sometimes showed wrong balances under load. Task: find the race and fix it without slowing the API. Action: I reproduced it with a JMeter test, found a read-then-update pattern in two concurrent requests, and replaced it with an atomic SQL update plus optimistic locking with a version column. Result: zero balance mismatches across festival traffic and a reusable load test for future changes.
29
You need to add a new payment method to a system that has a big if-else on payment type. How would you redesign it?
This breaks the Open/Closed principle. I would create a PaymentProcessor interface with a pay() method and one implementation per type, such as UpiProcessor and CardProcessor. A factory or a Spring map of beans keyed by type picks the right one. Adding a new method then means adding one new class without touching existing tested code, and each processor can be unit tested alone.
Parallel streams use the common ForkJoinPool and help only for large, CPU-bound, stateless work on sources that split well, like arrays and ArrayList. Avoid them for small data, I/O or blocking calls, LinkedList or iterate() sources, ordered operations like limit and findFirst, and shared mutable state. In a web server they compete for the same common pool, so measure before using them.
Tips to crack the SAP Java interview
Learn basic ERP concepts and what SAP S/4HANA, SAP BTP and SAP Analytics Cloud are used for.
Revise DSA, OOP and DBMS fundamentals, as SAP Labs technical interviews commonly test these core computer science topics.
Read about SAP's move to cloud and business AI, which shapes many current product roles.
Keep a one-minute story ready for every project on your CV: problem, your part, tools, result.
Practise the hard questions on this page aloud; SAP interviewers usually ask follow-ups on your first answer.
Frequently asked questions
How many rounds are there in the SAP Java interview?
Candidates usually go through 5 stages: Online assessment (aptitude + coding); Technical round 1; Technical round 2; Managerial round; HR round. The exact rounds change with the role, team, location and your experience, so confirm the process with the recruiter.
Which topics should I prepare for the SAP Java interview?
This practice set leans on Multithreading and Concurrency (7), Java 8+ Features and Streams (6), Strings and Exception Handling (5), OOP in Java (4). Revise those first, then practise explaining one or two of your own projects end to end, because most SAP interviewers ask you to walk through real work.
Are these the exact questions asked at SAP?
No. These are curated practice questions that match the skills and difficulty usually tested in product interviews like SAP's. They are not a leaked or verified list of past questions.
Where does SAP hire Java professionals in India?
SAP has large teams in Bengaluru, Gurugram, Pune, Mumbai. Openings and locations change often, so check the SAP careers page and filter by city and experience.