Skip to content

Amazon Java Interview Questions & Answers

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

  1. Online assessment (coding + work style survey)
  2. Technical round 1 (DSA)
  3. Technical round 2 (DSA or system design)
  4. Bar raiser round
  5. 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?

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.
02

Implement an LRU cache using LinkedHashMap.

Save to ▾
Show answer
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?

Save to ▾
Show answer
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?

Save to ▾
Show answer
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?

Save to ▾
Show answer
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.

Save to ▾
Show answer
Use a dedicated executor for I/O work. ExecutorService pool = Executors.newFixedThreadPool(4); CompletableFuture<User> user = CompletableFuture.supplyAsync(() -> userApi.get(id), pool); CompletableFuture<List<Order>> orders = CompletableFuture.supplyAsync(() -> orderApi.list(id), pool); Profile p = user.thenCombine(orders, Profile::new) .orTimeout(2, TimeUnit.SECONDS) .join();
07

An API calls three independent downstream services one after another and takes 900 ms. How would you speed it up?

Save to ▾
Show answer
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.
08

Find the top K most frequent words in a list.

Save to ▾
Show answer
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?

Save to ▾
Show answer
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.

Save to ▾
Show answer
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?

Save to ▾
Show answer
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?

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.
13

Compare the G1, ZGC and Parallel garbage collectors.

Save to ▾
Show answer
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.

Save to ▾
Show answer
Annotate the method and provide a fallback. @CircuitBreaker(name = "inventory", fallbackMethod = "stockUnknown") public Stock check(String sku) { return restClient.get().uri("/stock/{sku}", sku) .retrieve().body(Stock.class); } private Stock stockUnknown(String sku, Throwable t) { return Stock.unknown(sku); } # application.yml resilience4j.circuitbreaker.instances.inventory: failure-rate-threshold: 50 wait-duration-in-open-state: 10s
15

What is the difference between synchronized and ReentrantLock?

Save to ▾
Show answer
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?

Save to ▾
Show answer
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?

Save to ▾
Show answer
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?

Save to ▾
Show answer
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.
19

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.
20

Group a list of orders by city and sum the amount per city.

Save to ▾
Show answer
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?

Save to ▾
Show answer
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.

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.
23

Which JVM flags would you set to start a production service with a 4 GB heap, G1 and a heap dump on OOM?

Save to ▾
Show answer
A typical command is: java -Xms4g -Xmx4g \ -XX:+UseG1GC -XX:MaxGCPauseMillis=200 \ -XX:+HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath=/var/log/app \ -Xlog:gc*:file=/var/log/app/gc.log \ -jar app.jar In containers prefer -XX:MaxRAMPercentage=75 so the heap follows the container memory limit.
24

Explain the main memory areas of the JVM.

Save to ▾
Show answer
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?

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.
26

Implement a producer-consumer using BlockingQueue.

Save to ▾
Show answer
BlockingQueue handles waiting and signalling for you. BlockingQueue<Integer> q = new ArrayBlockingQueue<>(10); Runnable producer = () -> { for (int i = 0; i < 100; i++) { try { q.put(i); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } }; Runnable consumer = () -> { try { while (true) System.out.println(q.take()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }; put blocks when full and take blocks when empty.
27

Objects used as HashMap keys cannot be found after insertion. What could be wrong?

Save to ▾
Show answer
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?

Save to ▾
Show answer
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.

Save to ▾
Show answer
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.

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; }; }

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.

Java questions for similar companies