Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.
About Amazon hiring for Java roles
Amazon is a global technology company spanning e-commerce, cloud computing through AWS, devices, advertising and streaming. In India it runs large engineering, operations and analytics teams supporting both Amazon.in and global businesses. It hires for software development engineers, SDETs, quality assurance engineers, business intelligence engineers, data engineers and data scientists.
For Java roles, this Amazon practice set focuses most on Collections Framework (7), Spring Boot and Microservices (5), Multithreading and Concurrency (5), Java 8+ Features and Streams (4). It has 20 medium, 10 hard questions, so you can start easy and work up to the harder ones.
Company type
Product
Headquarters
Seattle, USA
Main India offices
Bengaluru, Hyderabad, Chennai, Pune, Gurugram
Amazon Java interview process
Online assessment (coding + work style survey)
Technical round 1 (DSA)
Technical round 2 (DSA or system design)
Bar raiser round
Hiring manager round
Typical pattern based on public candidate experiences. Rounds vary by role, team and year.
Solved for AmazonStart 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
A @Transactional method is not rolling back after an exception. What could be wrong?
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.
Access order plus removeEldestEntry gives LRU in a few lines.
class LruCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
LruCache(int capacity) {
super(16, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> e) {
return size() > capacity;
}
}
get and put are O(1).
03
When would you choose ArrayDeque over Stack and LinkedList?
Stack is a legacy synchronized class built on Vector, so it is slow and exposes index methods that break stack rules. LinkedList allocates a node per element. ArrayDeque is a resizable circular array with no per-element allocation, so push, pop, offer and poll are fast amortised O(1). Use ArrayDeque for both stacks and queues in single-threaded code; it does not accept null.
04
A HashMap shared by many threads sometimes loses updates. How do you fix it?
HashMap is not thread safe, so concurrent put calls can overwrite each other. Replace it with ConcurrentHashMap and use atomic methods instead of get-then-put, for example counts.merge(key, 1, Integer::sum) or computeIfAbsent for lazy creation. Collections.synchronizedMap also works but locks the whole map, which hurts throughput under contention.
05
You need a cache that evicts the least recently used item when full. How would you build it in Java?
Extend LinkedHashMap with accessOrder set to true and override removeEldestEntry to return true when size exceeds capacity. Each get moves the entry to the end, so the eldest is the least recently used. It is not thread safe, so wrap it with synchronization for shared use. In production prefer Caffeine, which offers size and time based eviction with high concurrency.
06
Run two tasks in parallel with CompletableFuture and combine their results.
Since the calls are independent, run them in parallel with CompletableFuture.supplyAsync on a dedicated executor or with virtual threads, then join with allOf. Total latency becomes roughly the slowest call, about 300 ms. Add a timeout per call with orTimeout and a fallback for failures so one slow service does not block the whole response. Structured concurrency is another option in newer Java.
Count with a map, then keep a min-heap of size K.
Map<String, Integer> cnt = new HashMap<>();
for (String w : words) cnt.merge(w, 1, Integer::sum);
PriorityQueue<String> pq = new PriorityQueue<>(
Comparator.comparingInt(cnt::get));
for (String w : cnt.keySet()) {
pq.offer(w);
if (pq.size() > k) pq.poll();
}
Time O(n log k). Reverse the heap contents for highest first.
09
Production shows Connection is not available, request timed out after 30000ms from HikariCP. What do you check?
The pool is exhausted. Check for connection leaks, where code holds connections without closing, by setting leakDetectionThreshold. Look for long transactions doing remote calls inside @Transactional, slow queries holding connections and a pool size too small for the thread count. Fix leaks, move external calls outside transactions, optimise slow queries and then size the pool from load tests.
10
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.
11
Your REST API returns stack traces to clients when errors happen. How do you design proper error handling?
Never expose stack traces; they leak internals. In Spring Boot use a @RestControllerAdvice with @ExceptionHandler methods that map domain exceptions to status codes, such as 404 for not found and 400 for validation. Return a consistent body, ideally RFC 7807 ProblemDetail, with a code, message and trace id. Log full details on the server with the same trace id.
12
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.
13
Compare the G1, ZGC and Parallel garbage collectors.
Parallel GC focuses on throughput and uses multiple threads but stops the application during collection. G1, the default since Java 9, splits the heap into regions and targets a pause time goal, which suits most server apps. ZGC is a low latency collector with pauses typically under a millisecond even on very large heaps, and is generational from Java 21. Choose based on latency versus throughput needs.
14
Configure a Resilience4j circuit breaker on a client call in Spring Boot.
synchronized is a built-in keyword that locks a monitor and releases it automatically at block exit. ReentrantLock is an explicit lock that adds tryLock with timeout, interruptible locking, fairness options and multiple Condition objects, but you must unlock in a finally block. Both are reentrant. Prefer synchronized for simple cases and ReentrantLock when you need its extra features.
16
Why must you be careful when initial capacity of a HashMap is too small?
If a HashMap starts small and grows large, it resizes many times; each resize allocates a new array and rehashes every entry, which costs CPU and creates garbage. When the expected size is known, use HashMap.newHashMap(n) in Java 19 or later, or set capacity to n divided by 0.75. Too large a capacity wastes memory, so size it to real data.
17
How would you write a simple thread safe rate limiter in Java?
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.
18
How would you split a monolith into microservices?
Do not split everything at once. Identify bounded contexts with the business, such as orders, payments and catalogue, and pick a module with clear boundaries and high change rate first. Use the strangler fig pattern: route its traffic through a gateway to the new service, give it its own database and sync data through events. Add observability and CI/CD before scaling out further.
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.
20
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.
21
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.
22
Using streams, find the employee with the highest salary in each department.
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.
23
Which JVM flags would you set to start a production service with a 4 GB heap, G1 and a heap dump on OOM?
The heap stores all objects and is shared by threads; it is managed by the garbage collector. Each thread has its own stack holding frames with local variables and partial results. Metaspace (native memory since Java 8) stores class metadata. There are also the program counter register and native method stacks. StackOverflowError comes from the stack and OutOfMemoryError usually from heap or metaspace.
25
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.
26
Implement a producer-consumer using BlockingQueue.
Most likely the class overrides equals() but not hashCode(), or neither, so equal keys land in different buckets. Another cause is a mutable key: a field used in hashCode() was changed after insertion, so the lookup goes to a different bucket. The fix is to implement both methods on the same fields and use immutable keys such as String, records or final classes.
28
Two users booking the last seat both succeed. How do you prevent double booking?
This is a race between read and write. Use a database guarantee: a unique constraint on seat and show, an atomic conditional update like UPDATE seats SET status = 'BOOKED' WHERE id = ? AND status = 'FREE' and check the affected row count, or pessimistic locking with SELECT FOR UPDATE. Optimistic locking with a version column also works, retrying or failing the loser.
29
Read a large text file line by line efficiently and count lines containing ERROR.
Stream the file lazily so it never loads fully into memory.
Path p = Path.of("app.log");
try (Stream<String> lines = Files.lines(p)) {
long errors = lines
.filter(l -> l.contains("ERROR"))
.count();
System.out.println(errors);
}
try-with-resources closes the file handle. BufferedReader.readLine() in a loop is an equally good option.
30
Write a sealed interface with records and a switch that computes area.
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;
};
}
Tips to crack the Amazon Java interview
Prepare STAR-format stories for each Amazon Leadership Principle, such as Customer Obsession, Ownership and Dive Deep.
Practise medium-level DSA problems on arrays, trees, graphs and dynamic programming, explaining time and space complexity aloud.
For BIE or data roles, practise SQL window functions and metric-driven case questions on e-commerce funnels and delivery operations.
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; Amazon interviewers usually ask follow-ups on your first answer.
Frequently asked questions
How many rounds are there in the Amazon Java interview?
Candidates usually go through 5 stages: Online assessment (coding + work style survey); Technical round 1 (DSA); Technical round 2 (DSA or system design); Bar raiser round; Hiring manager 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 Amazon Java interview?
This practice set leans on Collections Framework (7), Spring Boot and Microservices (5), Multithreading and Concurrency (5), Java 8+ Features and Streams (4). Revise those first, then practise explaining one or two of your own projects end to end, because most Amazon interviewers ask you to walk through real work.
Are these the exact questions asked at Amazon?
No. These are curated practice questions that match the skills and difficulty usually tested in product interviews like Amazon's. They are not a leaked or verified list of past questions.
Where does Amazon hire Java professionals in India?
Amazon has large teams in Bengaluru, Hyderabad, Chennai, Pune, Gurugram. Openings and locations change often, so check the Amazon careers page and filter by city and experience.