Java 26 Interview Questions & Answers - Comprehensive Guide Table of Contents Collections Framework HashMap Internals Set Implementations Queue & Deque Comparable vs Comparator Advanced Collections Concurrent Collections Interview MCQs Coding Problems System Design & Architecture Collections Framework ArrayList vs LinkedList ArrayList: Dynamic array implementation O(1) for get/set operations O(n) for add/remove at arbitrary positions Better for random access Memory overhead: minimal (stores contiguous elements) LinkedList: Doubly-linked list implementation O(n) for get/set operations O(1) for add/remove at ends Better for frequent insertions/deletions Memory overhead: more (stores nodes with prev/next references) java // ArrayList - Best for frequent access List arrayList = new ArrayList<>(); arrayList.add("A"); // O(1) arrayList.get(0); // O(1) // LinkedList - Best for frequent modifications at ends List linkedList = new LinkedList<>(); linkedList.add("A"); // O(1) linkedList.addFirst("B"); // O(1) linkedList.removeLast(); // O(1) Vector vs ArrayList Feature Vector ArrayList Synchronized Yes (thread-safe) No (not thread-safe) Performance Slower Faster Capacity Increment Doubles by default Increases by 50% Legacy Java 1.0 (legacy) Java 1.2 (modern) java // Vector - Thread-safe but slower Vector vector = new Vector<>(); vector.add("A"); // Synchronized method // ArrayList - Not thread-safe but faster ArrayList arrayList = new ArrayList<>(); arrayList.add("A"); // Not synchronized HashMap Internals HashMap Internal Structure Java 8+ Implementation: Array of Node (buckets) Each node can be a linked list or tree (TreeNode) Default initial capacity: 16 Default load factor: 0.75 Threshold = capacity * load factor Key Points: Hashing: hashCode() determines bucket index Collision Resolution: Chaining (linked list or tree) Treeification: When list length >= 8 and capacity >= 64 Untreeification: When tree size <= 6 java // Internal representation (simplified) class Node { final int hash; final K key; V value; Node next; // For linked list TreeNode next; // For tree nodes } // Put operation flow public V put(K key, V value) { // 1. Calculate hash int hash = hash(key); // 2. Find bucket index int index = hash & (n - 1); // 3. If bucket empty - create new node // 4. Else - check existing nodes // - If key matches: replace value // - Else: add to chain/tree } LinkedHashMap Extends HashMap with doubly-linked list Maintains insertion order Slightly slower than HashMap Good for LRU cache implementation (access-order mode) java LinkedHashMap map = new LinkedHashMap<>(); map.put("A", 1); map.put("B", 2); map.put("C", 3); // Iteration maintains insertion order for (Map.Entry entry : map.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } // Output: A=1, B=2, C=3 // LRU Cache with access-order LinkedHashMap lruCache = new LinkedHashMap<>(16, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > 100; // Max size 100 } }; TreeMap Red-Black tree based implementation Maintains sorted order (natural or custom comparator) O(log n) for put, get, remove operations NavigableMap interface support java TreeMap treeMap = new TreeMap<>(); treeMap.put("B", 2); treeMap.put("A", 1); treeMap.put("C", 3); // Natural order: A, B, C System.out.println(treeMap.firstKey()); // A System.out.println(treeMap.lastKey()); // C // Custom comparator for reverse order TreeMap reverseMap = new TreeMap<>(Comparator.reverseOrder()); reverseMap.put("B", 2); reverseMap.put("A", 1); reverseMap.put("C", 3); // Order: C, B, A Hash Collision Definition: When two different keys produce the same bucket index. Handling in Java: Chaining: Store multiple entries in same bucket Java 8+ Improvement: Convert to balanced tree when chain length > 8 Best Practices to Reduce Collisions: Implement good hashCode() distribution Use proper load factor Use immutable keys java // Bad hashCode implementation class BadKey { String id; @Override public int hashCode() { return 0; // All keys collide - terrible! } } // Good hashCode implementation class GoodKey { String id; @Override public int hashCode() { return Objects.hash(id); } } equals() vs hashCode() Contract: If two objects are equal (equals() returns true), they must have same hashCode() If objects have same hashCode, they may or may not be equal hashCode() should be consistent across invocations java class Employee { private String name; private int id; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return id == employee.id && Objects.equals(name, employee.name); } @Override public int hashCode() { return Objects.hash(name, id); // Must be consistent with equals } } // Usage in HashMap Employee e1 = new Employee("John", 1); Employee e2 = new Employee("John", 1); Map map = new HashMap<>(); map.put(e1, "Value"); System.out.println(map.get(e2)); // "Value" - works due to proper equals/hashCode Set Implementations HashSet vs LinkedHashSet vs TreeSet Feature HashSet LinkedHashSet TreeSet Order No guaranteed order Insertion order Sorted (natural/comparator) Performance O(1) O(1) O(log n) Internal HashMap LinkedHashMap TreeMap Null values Allows Allows Allows (only if comparator supports) Thread-safe No No No java // HashSet - Fast, no order Set hashSet = new HashSet<>(); hashSet.add("B"); hashSet.add("A"); hashSet.add("C"); // Order: unpredictable // LinkedHashSet - Maintains insertion order Set linkedSet = new LinkedHashSet<>(); linkedSet.add("B"); linkedSet.add("A"); linkedSet.add("C"); // Order: B, A, C // TreeSet - Sorted Set treeSet = new TreeSet<>(); treeSet.add("B"); treeSet.add("A"); treeSet.add("C"); // Order: A, B, C Queue & Deque PriorityQueue Heap-based implementation (min-heap by default) O(log n) for offer/poll operations Not thread-safe Ordering: natural or custom comparator java // Natural ordering (min-heap) PriorityQueue pq = new PriorityQueue<>(); pq.offer(3); pq.offer(1); pq.offer(2); System.out.println(pq.poll()); // 1 // Max-heap with custom comparator PriorityQueue maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); maxHeap.offer(3); maxHeap.offer(1); maxHeap.offer(2); System.out.println(maxHeap.poll()); // 3 // Custom comparator for specific order PriorityQueue taskQueue = new PriorityQueue<>( (t1, t2) -> Integer.compare(t1.priority, t2.priority) ); ArrayDeque Resizable array implementation of Deque Better than Stack and LinkedList for queue/stack operations Not thread-safe O(1) amortized for add/remove at both ends java // As Stack (LIFO) Deque stack = new ArrayDeque<>(); stack.push("A"); stack.push("B"); System.out.println(stack.pop()); // B // As Queue (FIFO) Deque queue = new ArrayDeque<>(); queue.offer("A"); queue.offer("B"); System.out.println(queue.poll()); // A // Operations at both ends Deque deque = new ArrayDeque<>(); deque.addFirst(1); deque.addLast(2); deque.offerFirst(3); deque.offerLast(4); Queue vs Deque Queue: FIFO (First In First Out) offer(), poll(), peek() Single-ended Deque: Double Ended Queue Can operate at both ends Can be used as Queue (FIFO) or Stack (LIFO) addFirst(), addLast(), pollFirst(), pollLast() java // Queue interface methods Queue queue = new LinkedList<>(); queue.offer("A"); // Add to tail String head = queue.poll(); // Remove from head String front = queue.peek(); // View head // Deque interface methods Deque deque = new ArrayDeque<>(); deque.addFirst("A"); // Add to front deque.addLast("B"); // Add to back String first = deque.pollFirst(); // Remove from front String last = deque.pollLast(); // Remove from back Comparable vs Comparator Comparable Natural ordering (single sorting sequence) Implemented by the class itself Method: compareTo(T o) Used by Collections.sort() and TreeSet/TreeMap java class Student implements Comparable { String name; int id; @Override public int compareTo(Student other) { return Integer.compare(this.id, other.id); // Natural order by id } // Alternative: compare by name // return this.name.compareTo(other.name); } // Usage List students = getStudents(); Collections.sort(students); // Sorts by id Comparator Custom ordering (multiple sorting sequences) Separate from the class Method: compare(T o1, T o2) Useful for sorting in different ways java // Multiple comparators class NameComparator implements Comparator { @Override public int compare(Student s1, Student s2) { return s1.name.compareTo(s2.name); } } class AgeComparator implements Comparator { @Override public int compare(Student s1, Student s2) { return Integer.compare(s1.age, s2.age); } } // Usage with lambda List students = getStudents(); students.sort((s1, s2) -> s1.name.compareTo(s2.name)); // By name students.sort(Comparator.comparing(Student::getAge)); // By age students.sort(Comparator.comparing(Student::getName) .thenComparing(Student::getAge)); // Multiple criteria Collections.sort() java // With Comparable Collections.sort(list); // Natural order // With Comparator Collections.sort(list, comparator); Collections.sort(list, (a, b) -> a.length() - b.length()); // Modern approach list.sort(Comparator.naturalOrder()); list.sort(Comparator.reverseOrder()); list.sort(Comparator.comparing(String::length)); list.sort(Comparator.comparing(String::toLowerCase)); Binary Search java // Binary search in sorted array int[] arr = {1, 2, 3, 4, 5}; int index = Arrays.binarySearch(arr, 3); // 2 // Binary search in sorted List List list = Arrays.asList(1, 2, 3, 4, 5); int idx = Collections.binarySearch(list, 3); // 2 // With custom comparator List names = Arrays.asList("Alice", "Bob", "Charlie"); int pos = Collections.binarySearch(names, "Bob", String.CASE_INSENSITIVE_ORDER); // Implementation of binary search public int binarySearch(int[] arr, int target) { int left = 0, right = arr.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] == target) return mid; else if (arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; } Advanced Collections Reverse HashMap java // Reverse Map: invert key-value pairs public Map reverseMap(Map original) { Map reversed = new HashMap<>(); for (Map.Entry entry : original.entrySet()) { reversed.put(entry.getValue(), entry.getKey()); } return reversed; } // With duplicate values handling public Map> reverseMapWithDuplicates(Map original) { Map> reversed = new HashMap<>(); for (Map.Entry entry : original.entrySet()) { reversed.computeIfAbsent(entry.getValue(), k -> new ArrayList<>()) .add(entry.getKey()); } return reversed; } // Java 8 Streams approach Map map = Map.of("A", 1, "B", 2, "C", 3); Map reversed = map.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); Merge Maps java // Simple merge Map map1 = new HashMap<>(); map1.put("A", 1); map1.put("B", 2); Map map2 = new HashMap<>(); map2.put("B", 3); map2.put("C", 4); // Method 1: putAll (overwrites) Map merged = new HashMap<>(map1); merged.putAll(map2); // B becomes 3 // Method 2: merge with conflict resolution Map merged2 = new HashMap<>(map1); for (Map.Entry entry : map2.entrySet()) { merged2.merge(entry.getKey(), entry.getValue(), Integer::sum); // Or: (v1, v2) -> v1 + v2 // Or: (v1, v2) -> Math.max(v1, v2) } // Method 3: Streams Map merged3 = Stream.concat( map1.entrySet().stream(), map2.entrySet().stream() ).collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, Integer::sum // Conflict resolution )); Frequency Counter java // Count frequency of elements public Map frequencyCounter(List list) { return list.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); } // Manual approach public Map countFrequency(List list) { Map freq = new HashMap<>(); for (T item : list) { freq.put(item, freq.getOrDefault(item, 0) + 1); // or // freq.compute(item, (k, v) -> v == null ? 1 : v + 1); // or // freq.merge(item, 1, Integer::sum); } return freq; } // Character frequency in string public Map characterFrequency(String s) { return s.chars() .mapToObj(c -> (char) c) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); } // Example with words String text = "apple banana apple cherry banana apple"; Map wordFreq = Arrays.stream(text.split(" ")) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); // {apple=3, banana=2, cherry=1} Remove Duplicates java // From List public List removeDuplicates(List list) { // Using Set return new ArrayList<>(new LinkedHashSet<>(list)); // Preserves order // Using Streams return list.stream().distinct().collect(Collectors.toList()); } // From Array public int[] removeDuplicates(int[] arr) { return Arrays.stream(arr).distinct().toArray(); } // Remove duplicates while preserving order public List removeDuplicatesPreserveOrder(List list) { Set seen = new HashSet<>(); return list.stream() .filter(seen::add) // Only adds if not seen before .collect(Collectors.toList()); } // Custom object duplicates by specific field public List removeDuplicatesByField(List people) { Set seenNames = new HashSet<>(); return people.stream() .filter(p -> seenNames.add(p.getName())) .collect(Collectors.toList()); } Coding Problems Top-K Elements java // Using PriorityQueue (Min-Heap for K largest) public List topK(int[] nums, int k) { PriorityQueue minHeap = new PriorityQueue<>(); for (int num : nums) { minHeap.offer(num); if (minHeap.size() > k) { minHeap.poll(); // Remove smallest } } return new ArrayList<>(minHeap); } // Top K Frequent Elements public List topKFrequent(int[] nums, int k) { // 1. Count frequencies Map freq = new HashMap<>(); for (int num : nums) { freq.put(num, freq.getOrDefault(num, 0) + 1); } // 2. Use min-heap to keep top K PriorityQueue> heap = new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue)); for (Map.Entry entry : freq.entrySet()) { heap.offer(entry); if (heap.size() > k) { heap.poll(); } } // 3. Extract results List result = new ArrayList<>(); while (!heap.isEmpty()) { result.add(heap.poll().getKey()); } Collections.reverse(result); return result; } // Top K using Bucket Sort (O(n)) public List topKFrequentBucket(int[] nums, int k) { Map freq = new HashMap<>(); for (int num : nums) { freq.put(num, freq.getOrDefault(num, 0) + 1); } // Bucket sort by frequency List[] buckets = new List[nums.length + 1]; for (Map.Entry entry : freq.entrySet()) { int f = entry.getValue(); if (buckets[f] == null) { buckets[f] = new ArrayList<>(); } buckets[f].add(entry.getKey()); } List result = new ArrayList<>(); for (int i = buckets.length - 1; i >= 0 && result.size() < k; i--) { if (buckets[i] != null) { result.addAll(buckets[i]); } } return result; } LRU Cache (3 Implementations) Implementation 1: Using LinkedHashMap (Built-in) java class LRUCache1 extends LinkedHashMap { private final int capacity; public LRUCache1(int capacity) { super(capacity, 0.75f, true); // accessOrder = true this.capacity = capacity; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > capacity; } } Implementation 2: Using Custom Doubly LinkedList + HashMap java class LRUCache2 { private final int capacity; private final Map> map; private final DoublyLinkedList list; static class Node { K key; V value; Node prev; Node next; Node(K key, V value) { this.key = key; this.value = value; } } static class DoublyLinkedList { Node head; Node tail; void addToFront(Node node) { if (head == null) { head = tail = node; } else { node.next = head; head.prev = node; head = node; } } void moveToFront(Node node) { if (node == head) return; remove(node); addToFront(node); } void remove(Node node) { if (node.prev != null) { node.prev.next = node.next; } else { head = node.next; } if (node.next != null) { node.next.prev = node.prev; } else { tail = node.prev; } node.prev = node.next = null; } Node removeLast() { if (tail == null) return null; Node last = tail; remove(last); return last; } } public LRUCache2(int capacity) { this.capacity = capacity; this.map = new HashMap<>(); this.list = new DoublyLinkedList<>(); } public V get(K key) { Node node = map.get(key); if (node == null) return null; list.moveToFront(node); return node.value; } public void put(K key, V value) { Node node = map.get(key); if (node != null) { node.value = value; list.moveToFront(node); } else { Node newNode = new Node<>(key, value); map.put(key, newNode); list.addToFront(newNode); if (map.size() > capacity) { Node removed = list.removeLast(); map.remove(removed.key); } } } } Implementation 3: Using ConcurrentHashMap (Thread-safe) java import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; class LRUCache3 { private final int capacity; private final ConcurrentHashMap> map; private final DoublyLinkedList list; private final ReentrantReadWriteLock lock; public LRUCache3(int capacity) { this.capacity = capacity; this.map = new ConcurrentHashMap<>(); this.list = new DoublyLinkedList<>(); this.lock = new ReentrantReadWriteLock(); } public V get(K key) { lock.readLock().lock(); try { Node node = map.get(key); if (node == null) return null; // Need write lock for moving to front lock.readLock().unlock(); lock.writeLock().lock(); try { list.moveToFront(node); } finally { lock.writeLock().unlock(); } lock.readLock().lock(); return node.value; } finally { lock.readLock().unlock(); } } public void put(K key, V value) { lock.writeLock().lock(); try { Node node = map.get(key); if (node != null) { node.value = value; list.moveToFront(node); } else { Node newNode = new Node<>(key, value); map.put(key, newNode); list.addToFront(newNode); if (map.size() > capacity) { Node removed = list.removeLast(); map.remove(removed.key); } } } finally { lock.writeLock().unlock(); } } } WeakHashMap java // WeakHashMap - entries removed when keys are garbage collected WeakHashMap weakMap = new WeakHashMap<>(); String key = new String("temp"); weakMap.put(key, "value"); System.out.println(weakMap.size()); // 1 key = null; // Remove strong reference System.gc(); // Suggest garbage collection System.out.println(weakMap.size()); // 0 (eventually) // Use case: Caching with automatic cleanup class CacheManager { private final WeakHashMap cache = new WeakHashMap<>(); public void put(String key, Object value) { cache.put(key, value); } public Object get(String key) { return cache.get(key); } } IdentityHashMap java // IdentityHashMap - uses reference equality (==) instead of equals() IdentityHashMap identityMap = new IdentityHashMap<>(); String key1 = new String("key"); String key2 = new String("key"); identityMap.put(key1, "value1"); identityMap.put(key2, "value2"); System.out.println(identityMap.size()); // 2 (two different objects) System.out.println(identityMap.get(key1)); // "value1" System.out.println(identityMap.get(key2)); // "value2" // Useful for serialization, object graph traversal EnumMap & EnumSet java // EnumMap - Optimized for enum keys enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } EnumMap tasks = new EnumMap<>(Day.class); tasks.put(Day.MONDAY, "Meeting"); tasks.put(Day.FRIDAY, "Review"); System.out.println(tasks.get(Day.MONDAY)); // EnumSet - Optimized bit-vector implementation enum Status { ACTIVE, INACTIVE, PENDING, CANCELLED } EnumSet activeStatuses = EnumSet.of(Status.ACTIVE, Status.PENDING); EnumSet allStatuses = EnumSet.allOf(Status.class); EnumSet noneStatuses = EnumSet.noneOf(Status.class); // Use case: Filtering public boolean isValidStatus(Status status) { Set valid = EnumSet.of(Status.ACTIVE, Status.PENDING); return valid.contains(status); } Concurrent Collections CopyOnWriteArrayList java // Thread-safe, optimized for read-heavy scenarios CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); list.add("A"); list.add("B"); list.addIfAbsent("C"); // Snapshot iteration - no ConcurrentModificationException for (String item : list) { // Can safely modify while iterating if (item.equals("B")) { list.add("D"); // Works but creates new copy } } // Characteristics: // 1. All modifications create new copy of underlying array // 2. Iterators see snapshot of array at creation time // 3. Good for read-many, write-few scenarios // 4. Memory overhead for writes ConcurrentHashMap java // Thread-safe HashMap for high concurrency ConcurrentHashMap map = new ConcurrentHashMap<>(); // Atomic operations map.putIfAbsent("key", 1); // Only puts if absent map.computeIfAbsent("key", k -> 1); // Only computes if absent map.computeIfPresent("key", (k, v) -> v + 1); // Modifies if present map.merge("key", 1, Integer::sum); // Combines values // Batch operations (Java 8+) map.forEach((k, v) -> System.out.println(k + "=" + v)); map.forEachValue(2, v -> System.out.println(v)); // Parallel with threshold map.search(1, (k, v) -> v > 10 ? k : null); // Comparison with synchronized HashMap // ConcurrentHashMap: Segment/Node-level locking (better concurrency) // Collections.synchronizedMap(): Whole map locking (poor concurrency) // Internal structure (Java 8+) // - Array of Node (buckets) // - CAS operations for node manipulation // - Tree bins for high collision scenarios BlockingQueue java // BlockingQueue implementations BlockingQueue arrayQueue = new ArrayBlockingQueue<>(10); BlockingQueue linkedQueue = new LinkedBlockingQueue<>(); BlockingQueue priorityQueue = new PriorityBlockingQueue<>(); BlockingQueue syncQueue = new SynchronousQueue<>(); BlockingQueue transferQueue = new LinkedTransferQueue<>(); // Producer-Consumer example class Producer implements Runnable { private BlockingQueue queue; public Producer(BlockingQueue queue) { this.queue = queue; } @Override public void run() { try { queue.put("Message"); // Blocks if full } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } class Consumer implements Runnable { private BlockingQueue queue; public Consumer(BlockingQueue queue) { this.queue = queue; } @Override public void run() { try { String message = queue.take(); // Blocks if empty System.out.println(message); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } // Usage BlockingQueue queue = new ArrayBlockingQueue<>(5); ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new Producer(queue)); executor.execute(new Consumer(queue)); Interview MCQs Question 1: Collections Framework Q: Which collection is best for maintaining insertion order with O(1) access? A. TreeSet B. HashSet C. LinkedHashSet D. PriorityQueue Answer: C - LinkedHashSet maintains insertion order with O(1) operations. Question 2: HashMap Q: What happens when HashMap's load factor is 0.5? A. Memory usage increases, collisions decrease B. Memory usage decreases, collisions increase C. Performance improves for all operations D. No effect on performance Answer: A - Lower load factor means more bucket space, less collisions but more memory usage. Question 3: equals() and hashCode() Q: Given two objects with same hashCode but different equals(), what happens in HashMap? A. Both objects are stored in same bucket as separate entries B. Second object overwrites first C. Exception is thrown D. Objects are merged Answer: A - Same hashCode means same bucket, but different equals means they're different entries. Question 4: Concurrent Collections Q: Which collection provides the best performance for multi-threaded read-write scenarios? A. Vector B. Synchronized List C. CopyOnWriteArrayList D. ConcurrentHashMap Answer: D - ConcurrentHashMap provides fine-grained locking for better concurrency. Question 5: Queue Operations Q: Which method does NOT throw exception when queue is empty? A. remove() B. element() C. poll() D. All of the above Answer: C - poll() returns null, others throw exceptions. JUnit 5 Tests java import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; import java.util.*; class CollectionTests { @Test void testArrayListVsLinkedListPerformance() { List arrayList = new ArrayList<>(); List linkedList = new LinkedList<>(); // Test add at end long start = System.nanoTime(); for (int i = 0; i < 100000; i++) arrayList.add(i); long arrayListEndAdd = System.nanoTime() - start; start = System.nanoTime(); for (int i = 0; i < 100000; i++) linkedList.add(i); long linkedListEndAdd = System.nanoTime() - start; assertTrue(linkedListEndAdd > arrayListEndAdd); // LinkedList slower for add } @Test void testHashMapPutAndGet() { Map map = new HashMap<>(); map.put("A", 1); map.put("B", 2); assertEquals(1, map.get("A")); assertEquals(2, map.get("B")); assertNull(map.get("C")); } @Test void testSetOperations() { Set set = new HashSet<>(); set.add(1); set.add(2); set.add(1); // Duplicate assertEquals(2, set.size()); assertTrue(set.contains(1)); assertTrue(set.contains(2)); } @Test void testMapOperations() { Map map = new HashMap<>(); // Using computeIfAbsent map.computeIfAbsent("key", k -> 1); assertEquals(1, map.get("key")); // Using merge map.merge("key", 2, Integer::sum); assertEquals(3, map.get("key")); } @Test @DisplayName("Test PriorityQueue ordering") void testPriorityQueue() { PriorityQueue queue = new PriorityQueue<>(); queue.offer(3); queue.offer(1); queue.offer(2); assertEquals(1, queue.poll()); assertEquals(2, queue.poll()); assertEquals(3, queue.poll()); } @Test void testConcurrentModification() { List list = new ArrayList<>(Arrays.asList("A", "B", "C")); assertThrows(ConcurrentModificationException.class, () -> { for (String item : list) { if (item.equals("B")) { list.remove(item); // Throws ConcurrentModificationException } } }); } @ParameterizedTest @ValueSource(strings = {"A", "B", "C"}) void testMapContainsKey(String key) { Map map = Map.of("A", 1, "B", 2, "C", 3); assertTrue(map.containsKey(key)); } } Real Interview Questions from FAANG/Banks 1. Design a thread-safe LRU Cache (Google) java class ThreadSafeLRUCache { private final int capacity; private final ConcurrentHashMap> cache; private final DoublyLinkedList list; private final ReentrantReadWriteLock lock; public ThreadSafeLRUCache(int capacity) { this.capacity = capacity; this.cache = new ConcurrentHashMap<>(); this.list = new DoublyLinkedList<>(); this.lock = new ReentrantReadWriteLock(); } public V get(K key) { lock.readLock().lock(); try { Node node = cache.get(key); if (node == null) return null; // Move to front (needs write lock) lock.readLock().unlock(); lock.writeLock().lock(); try { list.moveToFront(node); } finally { lock.writeLock().unlock(); lock.readLock().lock(); } return node.value; } finally { lock.readLock().unlock(); } } // ... rest of implementation } 2. Find All Anagrams in a String (Facebook) java public List findAnagrams(String s, String p) { List result = new ArrayList<>(); if (s.length() < p.length()) return result; Map pCount = new HashMap<>(); Map windowCount = new HashMap<>(); // Initialize pattern frequency for (char c : p.toCharArray()) { pCount.put(c, pCount.getOrDefault(c, 0) + 1); } // Slide window for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); windowCount.put(c, windowCount.getOrDefault(c, 0) + 1); if (i >= p.length()) { char left = s.charAt(i - p.length()); windowCount.put(left, windowCount.get(left) - 1); if (windowCount.get(left) == 0) { windowCount.remove(left); } } if (windowCount.equals(pCount)) { result.add(i - p.length() + 1); } } return result; } 3. Serialize and Deserialize Binary Tree (Amazon) java class Codec { private static final String SEP = ","; private static final String NULL = "#"; // Serializes a tree to a single string. public String serialize(TreeNode root) { StringBuilder sb = new StringBuilder(); serializeHelper(root, sb); return sb.toString(); } private void serializeHelper(TreeNode node, StringBuilder sb) { if (node == null) { sb.append(NULL).append(SEP); return; } sb.append(node.val).append(SEP); serializeHelper(node.left, sb); serializeHelper(node.right, sb); } // Deserializes encoded data to tree. public TreeNode deserialize(String data) { Queue queue = new LinkedList<>(Arrays.asList(data.split(SEP))); return deserializeHelper(queue); } private TreeNode deserializeHelper(Queue queue) { String val = queue.poll(); if (val.equals(NULL)) return null; TreeNode node = new TreeNode(Integer.parseInt(val)); node.left = deserializeHelper(queue); node.right = deserializeHelper(queue); return node; } } 4. Find Median from Data Stream (Goldman Sachs) java class MedianFinder { private PriorityQueue maxHeap; // Lower half private PriorityQueue minHeap; // Upper half public MedianFinder() { maxHeap = new PriorityQueue<>(Collections.reverseOrder()); minHeap = new PriorityQueue<>(); } public void addNum(int num) { maxHeap.offer(num); minHeap.offer(maxHeap.poll()); if (maxHeap.size() < minHeap.size()) { maxHeap.offer(minHeap.poll()); } } public double findMedian() { if (maxHeap.size() > minHeap.size()) { return maxHeap.peek(); } return (maxHeap.peek() + minHeap.peek()) / 2.0; } } 5. Word Ladder (Microsoft) java public int ladderLength(String beginWord, String endWord, List wordList) { Set dict = new HashSet<>(wordList); if (!dict.contains(endWord)) return 0; Queue queue = new LinkedList<>(); queue.offer(beginWord); int level = 1; while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { String word = queue.poll(); char[] chars = word.toCharArray(); for (int j = 0; j < chars.length; j++) { char original = chars[j]; for (char c = 'a'; c <= 'z'; c++) { if (c == original) continue; chars[j] = c; String transformed = new String(chars); if (transformed.equals(endWord)) { return level + 1; } if (dict.remove(transformed)) { queue.offer(transformed); } } chars[j] = original; } } level++; } return 0; } Top K Elements Find Top K Frequent Elements (LeetCode 347) java public int[] topKFrequent(int[] nums, int k) { // Count frequencies using HashMap Map count = new HashMap<>(); for (int num : nums) { count.put(num, count.getOrDefault(num, 0) + 1); } // Use min-heap of size k PriorityQueue heap = new PriorityQueue<>( (a, b) -> count.get(a) - count.get(b) ); for (int num : count.keySet()) { heap.offer(num); if (heap.size() > k) { heap.poll(); } } // Extract result int[] result = new int[k]; for (int i = k - 1; i >= 0; i--) { result[i] = heap.poll(); } return result; } Find Kth Largest Element (LeetCode 215) java public int findKthLargest(int[] nums, int k) { // Method 1: Min-heap of size k PriorityQueue heap = new PriorityQueue<>(); for (int num : nums) { heap.offer(num); if (heap.size() > k) { heap.poll(); } } return heap.peek(); // Method 2: QuickSelect (average O(n)) // Method 3: Sort (O(n log n)) } // QuickSelect implementation public int quickSelect(int[] nums, int k) { int left = 0, right = nums.length - 1; k = nums.length - k; // Convert to kth smallest while (left < right) { int pivot = partition(nums, left, right); if (pivot < k) left = pivot + 1; else if (pivot > k) right = pivot - 1; else break; } return nums[k]; } private int partition(int[] nums, int left, int right) { int pivot = nums[right]; int i = left; for (int j = left; j < right; j++) { if (nums[j] <= pivot) { swap(nums, i, j); i++; } } swap(nums, i, right); return i; } LRU Cache Full Implementation with Doubly LinkedList java class LRUCache { private final int capacity; private final Map cache; private final DoublyLinkedList list; private static class Node { int key; int value; Node prev; Node next; Node(int key, int value) { this.key = key; this.value = value; } } private static class DoublyLinkedList { private Node head; private Node tail; void addToFront(Node node) { if (head == null) { head = tail = node; } else { node.next = head; head.prev = node; head = node; } } void moveToFront(Node node) { if (node == head) return; remove(node); addToFront(node); } void remove(Node node) { if (node.prev != null) { node.prev.next = node.next; } else { head = node.next; } if (node.next != null) { node.next.prev = node.prev; } else { tail = node.prev; } node.prev = node.next = null; } Node removeLast() { if (tail == null) return null; Node last = tail; remove(last); return last; } } public LRUCache(int capacity) { this.capacity = capacity; this.cache = new HashMap<>(); this.list = new DoublyLinkedList(); } public int get(int key) { Node node = cache.get(key); if (node == null) return -1; list.moveToFront(node); return node.value; } public void put(int key, int value) { Node node = cache.get(key); if (node != null) { node.value = value; list.moveToFront(node); } else { Node newNode = new Node(key, value); cache.put(key, newNode); list.addToFront(newNode); if (cache.size() > capacity) { Node removed = list.removeLast(); cache.remove(removed.key); } } } } Immutable Collections java import java.util.*; public class ImmutableCollectionsDemo { public static void main(String[] args) { // Java 9+ immutable collections List immutableList = List.of("A", "B", "C"); Set immutableSet = Set.of(1, 2, 3); Map immutableMap = Map.of("A", 1, "B", 2); // Custom immutable class final class ImmutablePerson { private final String name; private final int age; private final List hobbies; public ImmutablePerson(String name, int age, List hobbies) { this.name = name; this.age = age; // Defensive copy this.hobbies = new ArrayList<>(hobbies); } public String getName() { return name; } public int getAge() { return age; } public List getHobbies() { return new ArrayList<>(hobbies); // Return copy } } // Using Collections.unmodifiableXXX() List modifiable = new ArrayList<>(Arrays.asList("A", "B")); List unmodifiable = Collections.unmodifiableList(modifiable); // Throws UnsupportedOperationException // unmodifiable.add("C"); // Original list still modifiable modifiable.add("C"); System.out.println(unmodifiable); // [A, B, C] // Truly immutable with copy List trulyImmutable = List.copyOf(modifiable); } } JUnit Tests Comprehensive Test Suite java import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.*; import static org.junit.jupiter.api.Assertions.*; import java.util.*; import java.util.stream.*; class CollectionsTestSuite { @Nested @DisplayName("List Tests") class ListTests { @Test @DisplayName("ArrayList should preserve insertion order") void testArrayListOrder() { List list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); assertIterableEquals(Arrays.asList("A", "B", "C"), list); } @Test @DisplayName("LinkedList should support FIFO operations") void testLinkedListQueue() { LinkedList list = new LinkedList<>(); list.offer("A"); list.offer("B"); assertEquals("A", list.poll()); assertEquals("B", list.poll()); assertNull(list.poll()); } } @Nested @DisplayName("Map Tests") class MapTests { @Test @DisplayName("HashMap should handle null values") void testHashMapNullValues() { Map map = new HashMap<>(); map.put("A", null); map.put(null, "B"); assertNull(map.get("A")); assertEquals("B", map.get(null)); } @ParameterizedTest @MethodSource("mapProvider") void testMapOperations(Map map) { map.put("A", 1); map.put("B", 2); assertEquals(1, map.get("A")); assertEquals(2, map.size()); } static Stream> mapProvider() { return Stream.of( new HashMap<>(), new LinkedHashMap<>(), new TreeMap<>(), new ConcurrentHashMap<>() ); } } @Nested @DisplayName("Set Tests") class SetTests { @Test @DisplayName("HashSet should not contain duplicates") void testHashSetNoDuplicates() { Set set = new HashSet<>(); set.add(1); set.add(2); set.add(1); // Duplicate assertEquals(2, set.size()); } @Test @DisplayName("TreeSet should maintain sorted order") void testTreeSetSorting() { Set set = new TreeSet<>(); set.add(3); set.add(1); set.add(2); assertIterableEquals(Arrays.asList(1, 2, 3), set); } } @Nested @DisplayName("Queue Tests") class QueueTests { @Test @DisplayName("PriorityQueue should order by natural order") void testPriorityQueueOrder() { PriorityQueue pq = new PriorityQueue<>(); pq.offer(3); pq.offer(1); pq.offer(2); assertAll( () -> assertEquals(1, pq.poll()), () -> assertEquals(2, pq.poll()), () -> assertEquals(3, pq.poll()) ); } } } Collections, Arrays, Strings Common Utility Methods java public class CollectionUtils { // Collections methods public static void collectionsExamples() { List list = Arrays.asList(1, 2, 3, 4, 5); Collections.reverse(list); // [5, 4, 3, 2, 1] Collections.shuffle(list); // Random order Collections.sort(list); // Sort ascending Collections.sort(list, Comparator.reverseOrder()); // Descending Collections.rotate(list, 2); // Rotate right by 2 int max = Collections.max(list); int min = Collections.min(list); int count = Collections.frequency(list, 3); List unmodifiable = Collections.unmodifiableList(list); List synchronizedList = Collections.synchronizedList(list); } // Arrays methods public static void arraysExamples() { int[] arr = {1, 2, 3, 4, 5}; Arrays.sort(arr); int index = Arrays.binarySearch(arr, 3); int[] copy = Arrays.copyOf(arr, 3); // [1, 2, 3] int[] range = Arrays.copyOfRange(arr, 1, 3); // [2, 3] boolean equals = Arrays.equals(arr, copy); String str = Arrays.toString(arr); // 2D arrays int[][] matrix = {{1, 2}, {3, 4}}; String deepStr = Arrays.deepToString(matrix); boolean deepEquals = Arrays.deepEquals(matrix, new int[][]{{1, 2}, {3, 4}}); } // Strings methods public static void stringExamples() { String s = "Hello World"; s.charAt(0); // 'H' s.length(); // 11 s.substring(0, 5); // "Hello" s.indexOf('o'); // 4 s.lastIndexOf('o'); // 7 String[] parts = s.split(" "); String joined = String.join("_", parts); // "Hello_World" // StringBuilder for efficient concatenation StringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(" "); sb.append("World"); String result = sb.toString(); // String formatting String formatted = String.format("%s %d %f", "Hello", 42, 3.14); } } HashMap & Set Advanced Custom HashMap Implementation java class CustomHashMap { private static class Entry { K key; V value; Entry next; Entry(K key, V value) { this.key = key; this.value = value; } } private Entry[] buckets; private int size; private static final int DEFAULT_CAPACITY = 16; private static final double LOAD_FACTOR = 0.75; @SuppressWarnings("unchecked") public CustomHashMap() { buckets = new Entry[DEFAULT_CAPACITY]; } private int hash(K key) { return key == null ? 0 : Math.abs(key.hashCode() % buckets.length); } public void put(K key, V value) { int index = hash(key); Entry existing = buckets[index]; while (existing != null) { if (existing.key == key || (existing.key != null && existing.key.equals(key))) { existing.value = value; return; } existing = existing.next; } Entry newEntry = new Entry<>(key, value); newEntry.next = buckets[index]; buckets[index] = newEntry; size++; if (size > buckets.length * LOAD_FACTOR) { resize(); } } public V get(K key) { int index = hash(key); Entry entry = buckets[index]; while (entry != null) { if (entry.key == key || (entry.key != null && entry.key.equals(key))) { return entry.value; } entry = entry.next; } return null; } @SuppressWarnings("unchecked") private void resize() { Entry[] oldBuckets = buckets; buckets = new Entry[oldBuckets.length * 2]; size = 0; for (Entry entry : oldBuckets) { while (entry != null) { put(entry.key, entry.value); entry = entry.next; } } } } Custom HashSet Implementation java class CustomHashSet { private static final Object PRESENT = new Object(); private final CustomHashMap map; public CustomHashSet() { map = new CustomHashMap<>(); } public boolean add(E e) { if (map.get(e) == null) { map.put(e, PRESENT); return true; } return false; } public boolean remove(E e) { if (map.get(e) != null) { map.put(e, null); return true; } return false; } public boolean contains(E e) { return map.get(e) != null; } public int size() { return map.size; } } Streams Java 8 Stream Examples java public class StreamExamples { // Filtering and Mapping public void filteringExamples() { List list = Arrays.asList("apple", "banana", "cherry", "date"); // Filter List filtered = list.stream() .filter(s -> s.length() > 5) .collect(Collectors.toList()); // ["banana", "cherry"] // Map List lengths = list.stream() .map(String::length) .collect(Collectors.toList()); // [5, 6, 6, 4] // Filter and map combined List longWordsLength = list.stream() .filter(s -> s.length() > 5) .map(String::length) .collect(Collectors.toList()); // [6, 6] } // Reduction Operations public void reductionExamples() { List numbers = Arrays.asList(1, 2, 3, 4, 5); // Sum int sum = numbers.stream() .reduce(0, Integer::sum); // 15 // Max Optional max = numbers.stream() .reduce(Integer::max); // 5 // Min Optional min = numbers.stream() .reduce(Integer::min); // 1 // Product int product = numbers.stream() .reduce(1, (a, b) -> a * b); // 120 } // Grouping public void groupingExamples() { List people = Arrays.asList( new Person("Alice", 30, "Engineer"), new Person("Bob", 25, "Designer"), new Person("Charlie", 35, "Engineer") ); // Group by profession Map> byProfession = people.stream() .collect(Collectors.groupingBy(Person::getProfession)); // Count by profession Map countByProfession = people.stream() .collect(Collectors.groupingBy(Person::getProfession, Collectors.counting())); // Average age by profession Map avgAgeByProfession = people.stream() .collect(Collectors.groupingBy(Person::getProfession, Collectors.averagingInt(Person::getAge))); } // Advanced Operations public void advancedExamples() { List words = Arrays.asList("Hello", "World", "Java"); // FlatMap - flatten nested structures List chars = words.stream() .flatMap(s -> s.chars().mapToObj(c -> (char) c)) .collect(Collectors.toList()); // Peek - for debugging List processed = words.stream() .map(String::length) .peek(System.out::println) .collect(Collectors.toList()); // Distinct List duplicates = Arrays.asList(1, 2, 2, 3, 3, 3); List unique = duplicates.stream() .distinct() .collect(Collectors.toList()); // [1, 2, 3] // Sorted List sorted = duplicates.stream() .sorted() .collect(Collectors.toList()); // [1, 2, 2, 3, 3, 3] // Limit and Skip List firstThree = numbers.stream() .limit(3) .collect(Collectors.toList()); List skipFirst = numbers.stream() .skip(2) .collect(Collectors.toList()); } static class Person { String name; int age; String profession; // Constructor, getters } } Recursion & Backtracking Classic Problems java public class RecursionExamples { // 1. N-Queens Problem public List> solveNQueens(int n) { List> result = new ArrayList<>(); char[][] board = new char[n][n]; for (int i = 0; i < n; i++) { Arrays.fill(board[i], '.'); } solveNQueensHelper(board, 0, result); return result; } private void solveNQueensHelper(char[][] board, int row, List> result) { if (row == board.length) { result.add(constructBoard(board)); return; } for (int col = 0; col < board.length; col++) { if (isSafe(board, row, col)) { board[row][col] = 'Q'; solveNQueensHelper(board, row + 1, result); board[row][col] = '.'; } } } private boolean isSafe(char[][] board, int row, int col) { // Check column for (int i = 0; i < row; i++) { if (board[i][col] == 'Q') return false; } // Check diagonal up-left for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { if (board[i][j] == 'Q') return false; } // Check diagonal up-right for (int i = row - 1, j = col + 1; i >= 0 && j < board.length; i--, j++) { if (board[i][j] == 'Q') return false; } return true; } // 2. Subset Generation public List> subsets(int[] nums) { List> result = new ArrayList<>(); subsetsHelper(nums, 0, new ArrayList<>(), result); return result; } private void subsetsHelper(int[] nums, int start, List current, List> result) { result.add(new ArrayList<>(current)); for (int i = start; i < nums.length; i++) { current.add(nums[i]); subsetsHelper(nums, i + 1, current, result); current.remove(current.size() - 1); } } // 3. Permutations public List> permutations(int[] nums) { List> result = new ArrayList<>(); permutationsHelper(nums, 0, result); return result; } private void permutationsHelper(int[] nums, int start, List> result) { if (start == nums.length) { result.add(Arrays.stream(nums).boxed().collect(Collectors.toList())); return; } for (int i = start; i < nums.length; i++) { swap(nums, start, i); permutationsHelper(nums, start + 1, result); swap(nums, start, i); } } } Linked List Core Operations java class ListNode { int val; ListNode next; ListNode(int val) { this.val = val; } } public class LinkedListOperations { // 1. Reverse Linked List public ListNode reverseList(ListNode head) { ListNode prev = null; ListNode current = head; while (current != null) { ListNode next = current.next; current.next = prev; prev = current; current = next; } return prev; } // 2. Reverse using recursion public ListNode reverseListRecursive(ListNode head) { if (head == null || head.next == null) return head; ListNode newHead = reverseListRecursive(head.next); head.next.next = head; head.next = null; return newHead; } // 3. Detect Cycle public boolean hasCycle(ListNode head) { if (head == null) return false; ListNode slow = head; ListNode fast = head.next; while (slow != fast) { if (fast == null || fast.next == null) return false; slow = slow.next; fast = fast.next.next; } return true; } // 4. Find Middle public ListNode findMiddle(ListNode head) { ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } // 5. Merge Two Sorted Lists public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0); ListNode current = dummy; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { current.next = l1; l1 = l1.next; } else { current.next = l2; l2 = l2.next; } current = current.next; } current.next = l1 != null ? l1 : l2; return dummy.next; } // 6. Remove Nth Node From End public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); dummy.next = head; ListNode first = dummy; ListNode second = dummy; for (int i = 0; i <= n; i++) { first = first.next; } while (first != null) { first = first.next; second = second.next; } second.next = second.next.next; return dummy.next; } } Stack & Queue Implementation and Problems java public class StackQueueProblems { // 1. Min Stack class MinStack { private Stack stack; private Stack minStack; public MinStack() { stack = new Stack<>(); minStack = new Stack<>(); } public void push(int x) { stack.push(x); if (minStack.isEmpty() || x <= minStack.peek()) { minStack.push(x); } } public void pop() { if (stack.peek().equals(minStack.peek())) { minStack.pop(); } stack.pop(); } public int top() { return stack.peek(); } public int getMin() { return minStack.peek(); } } // 2. Queue using Two Stacks class MyQueue { private Stack s1; private Stack s2; public MyQueue() { s1 = new Stack<>(); s2 = new Stack<>(); } public void push(int x) { s1.push(x); } public int pop() { if (s2.isEmpty()) { while (!s1.isEmpty()) { s2.push(s1.pop()); } } return s2.pop(); } public int peek() { if (s2.isEmpty()) { while (!s1.isEmpty()) { s2.push(s1.pop()); } } return s2.peek(); } public boolean empty() { return s1.isEmpty() && s2.isEmpty(); } } // 3. Stack using Two Queues class MyStack { private Queue q1; private Queue q2; public MyStack() { q1 = new LinkedList<>(); q2 = new LinkedList<>(); } public void push(int x) { q2.offer(x); while (!q1.isEmpty()) { q2.offer(q1.poll()); } Queue temp = q1; q1 = q2; q2 = temp; } public int pop() { return q1.poll(); } public int top() { return q1.peek(); } public boolean empty() { return q1.isEmpty(); } } // 4. Valid Parentheses public boolean isValid(String s) { Stack stack = new Stack<>(); Map map = Map.of( ')', '(', '}', '{', ']', '[' ); for (char c : s.toCharArray()) { if (map.containsKey(c)) { if (stack.isEmpty() || stack.pop() != map.get(c)) { return false; } } else { stack.push(c); } } return stack.isEmpty(); } } Trees Binary Tree Operations java class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int val) { this.val = val; } } public class TreeOperations { // 1. Traversals public List inorder(TreeNode root) { List result = new ArrayList<>(); inorderHelper(root, result); return result; } private void inorderHelper(TreeNode node, List result) { if (node == null) return; inorderHelper(node.left, result); result.add(node.val); inorderHelper(node.right, result); } // 2. Level Order Traversal public List> levelOrder(TreeNode root) { List> result = new ArrayList<>(); if (root == null) return result; Queue queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { int size = queue.size(); List level = new ArrayList<>(); for (int i = 0; i < size; i++) { TreeNode node = queue.poll(); level.add(node.val); if (node.left != null) queue.offer(node.left); if (node.right != null) queue.offer(node.right); } result.add(level); } return result; } // 3. Maximum Depth public int maxDepth(TreeNode root) { if (root == null) return 0; return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)); } // 4. Check Balanced public boolean isBalanced(TreeNode root) { return checkBalance(root) != -1; } private int checkBalance(TreeNode node) { if (node == null) return 0; int left = checkBalance(node.left); int right = checkBalance(node.right); if (left == -1 || right == -1 || Math.abs(left - right) > 1) { return -1; } return 1 + Math.max(left, right); } // 5. Lowest Common Ancestor public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if (root == null || root == p || root == q) return root; TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if (left != null && right != null) return root; return left != null ? left : right; } // 6. Validate BST public boolean isValidBST(TreeNode root) { return isValidBSTHelper(root, Long.MIN_VALUE, Long.MAX_VALUE); } private boolean isValidBSTHelper(TreeNode node, long min, long max) { if (node == null) return true; if (node.val <= min || node.val >= max) return false; return isValidBSTHelper(node.left, min, node.val) && isValidBSTHelper(node.right, node.val, max); } } Graphs Graph Algorithms java public class GraphAlgorithms { // 1. BFS public void bfs(Map> graph, int start) { Set visited = new HashSet<>(); Queue queue = new LinkedList<>(); queue.offer(start); visited.add(start); while (!queue.isEmpty()) { int node = queue.poll(); System.out.print(node + " "); for (int neighbor : graph.getOrDefault(node, Collections.emptyList())) { if (!visited.contains(neighbor)) { queue.offer(neighbor); visited.add(neighbor); } } } } // 2. DFS public void dfs(Map> graph, int start) { Set visited = new HashSet<>(); dfsHelper(graph, start, visited); } private void dfsHelper(Map> graph, int node, Set visited) { visited.add(node); System.out.print(node + " "); for (int neighbor : graph.getOrDefault(node, Collections.emptyList())) { if (!visited.contains(neighbor)) { dfsHelper(graph, neighbor, visited); } } } // 3. Detect Cycle in Directed Graph public boolean hasCycle(Map> graph) { Set visited = new HashSet<>(); Set recursionStack = new HashSet<>(); for (int node : graph.keySet()) { if (hasCycleHelper(graph, node, visited, recursionStack)) { return true; } } return false; } private boolean hasCycleHelper(Map> graph, int node, Set visited, Set recursionStack) { if (recursionStack.contains(node)) return true; if (visited.contains(node)) return false; visited.add(node); recursionStack.add(node); for (int neighbor : graph.getOrDefault(node, Collections.emptyList())) { if (hasCycleHelper(graph, neighbor, visited, recursionStack)) { return true; } } recursionStack.remove(node); return false; } // 4. Topological Sort (Kahn's Algorithm) public List topologicalSort(Map> graph, int vertices) { int[] indegree = new int[vertices]; for (List neighbors : graph.values()) { for (int neighbor : neighbors) { indegree[neighbor]++; } } Queue queue = new LinkedList<>(); for (int i = 0; i < vertices; i++) { if (indegree[i] == 0) { queue.offer(i); } } List result = new ArrayList<>(); while (!queue.isEmpty()) { int node = queue.poll(); result.add(node); for (int neighbor : graph.getOrDefault(node, Collections.emptyList())) { indegree[neighbor]--; if (indegree[neighbor] == 0) { queue.offer(neighbor); } } } return result.size() == vertices ? result : new ArrayList<>(); } // 5. Dijkstra's Algorithm public Map dijkstra(Map> graph, int start) { Map distances = new HashMap<>(); PriorityQueue pq = new PriorityQueue<>(Comparator.comparingInt(n -> n.distance)); pq.offer(new Node(start, 0)); distances.put(start, 0); while (!pq.isEmpty()) { Node current = pq.poll(); if (current.distance > distances.getOrDefault(current.id, Integer.MAX_VALUE)) { continue; } for (Edge edge : graph.getOrDefault(current.id, Collections.emptyList())) { int newDist = current.distance + edge.weight; if (newDist < distances.getOrDefault(edge.to, Integer.MAX_VALUE)) { distances.put(edge.to, newDist); pq.offer(new Node(edge.to, newDist)); } } } return distances; } static class Edge { int to; int weight; Edge(int to, int weight) { this.to = to; this.weight = weight; } } static class Node { int id; int distance; Node(int id, int distance) { this.id = id; this.distance = distance; } } } Dynamic Programming Classic DP Problems java public class DynamicProgramming { // 1. Longest Common Subsequence public int longestCommonSubsequence(String text1, String text2) { int m = text1.length(), n = text2.length(); int[][] dp = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (text1.charAt(i - 1) == text2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } } } return dp[m][n]; } // 2. Longest Increasing Subsequence public int lengthOfLIS(int[] nums) { int[] dp = new int[nums.length]; Arrays.fill(dp, 1); int max = 1; for (int i = 1; i < nums.length; i++) { for (int j = 0; j < i; j++) { if (nums[i] > nums[j]) { dp[i] = Math.max(dp[i], dp[j] + 1); } } max = Math.max(max, dp[i]); } return max; } // 3. Coin Change public int coinChange(int[] coins, int amount) { int[] dp = new int[amount + 1]; Arrays.fill(dp, amount + 1); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int coin : coins) { if (i >= coin) { dp[i] = Math.min(dp[i], dp[i - coin] + 1); } } } return dp[amount] > amount ? -1 : dp[amount]; } // 4. House Robber public int rob(int[] nums) { if (nums.length == 0) return 0; if (nums.length == 1) return nums[0]; int prev2 = nums[0]; int prev1 = Math.max(nums[0], nums[1]); for (int i = 2; i < nums.length; i++) { int current = Math.max(prev1, prev2 + nums[i]); prev2 = prev1; prev1 = current; } return prev1; } // 5. 0/1 Knapsack public int knapsack(int[] weights, int[] values, int capacity) { int n = weights.length; int[][] dp = new int[n + 1][capacity + 1]; for (int i = 1; i <= n; i++) { for (int w = 1; w <= capacity; w++) { if (weights[i - 1] <= w) { dp[i][w] = Math.max( dp[i - 1][w], values[i - 1] + dp[i - 1][w - weights[i - 1]] ); } else { dp[i][w] = dp[i - 1][w]; } } } return dp[n][capacity]; } } Concurrency Thread-Safe Operations java public class ConcurrencyExamples { // 1. Thread-safe Counter class Counter { private int count; private final ReentrantLock lock = new ReentrantLock(); public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } } // 2. Producer-Consumer class ProducerConsumer { private final int capacity = 5; private final Queue queue = new LinkedList<>(); private final Object lock = new Object(); public void produce() throws InterruptedException { synchronized (lock) { while (queue.size() == capacity) { lock.wait(); } queue.offer((int) (Math.random() * 100)); System.out.println("Produced: " + queue.peek()); lock.notifyAll(); } } public void consume() throws InterruptedException { synchronized (lock) { while (queue.isEmpty()) { lock.wait(); } int value = queue.poll(); System.out.println("Consumed: " + value); lock.notifyAll(); } } } // 3. Semaphore Example class ParkingLot { private final Semaphore semaphore; private final int capacity; private int currentCars = 0; public ParkingLot(int capacity) { this.capacity = capacity; this.semaphore = new Semaphore(capacity, true); } public void parkCar(String carId) throws InterruptedException { semaphore.acquire(); currentCars++; System.out.println(carId + " parked. Cars: " + currentCars); } public void leaveCar(String carId) { currentCars--; semaphore.release(); System.out.println(carId + " left. Cars: " + currentCars); } } // 4. CountDownLatch Example class ServiceInitializer { private final CountDownLatch latch = new CountDownLatch(3); private final ExecutorService executor = Executors.newFixedThreadPool(3); public void initializeServices() { List services = Arrays.asList( this::initDatabase, this::initCache, this::initNetwork ); services.forEach(service -> executor.submit(() -> { service.run(); latch.countDown(); })); try { latch.await(); // Wait for all services System.out.println("All services initialized"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } private void initDatabase() { // Simulate initialization try { Thread.sleep(1000); } catch (InterruptedException e) {} System.out.println("Database initialized"); } private void initCache() { try { Thread.sleep(800); } catch (InterruptedException e) {} System.out.println("Cache initialized"); } private void initNetwork() { try { Thread.sleep(1200); } catch (InterruptedException e) {} System.out.println("Network initialized"); } } } CompletableFuture Asynchronous Programming java public class CompletableFutureExamples { // 1. Basic Usage public void basicExample() throws Exception { CompletableFuture future = CompletableFuture.supplyAsync(() -> { sleep(1000); return "Hello"; }); future.thenAccept(System.out::println); // Hello future.thenApply(String::toUpperCase) .thenAccept(System.out::println); // HELLO } // 2. Combining Futures public void combineFutures() throws Exception { CompletableFuture future1 = CompletableFuture.supplyAsync(() -> "Hello"); CompletableFuture future2 = CompletableFuture.supplyAsync(() -> "World"); // Combine both results CompletableFuture combined = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2); System.out.println(combined.get()); // Hello World // Chain multiple futures CompletableFuture chained = future1.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " " + "World")); System.out.println(chained.get()); // Hello World } // 3. Error Handling public void errorHandling() throws Exception { CompletableFuture future = CompletableFuture.supplyAsync(() -> { if (true) throw new RuntimeException("Error!"); return "Success"; }); // Handle error future.exceptionally(throwable -> "Fallback value") .thenAccept(System.out::println); // Fallback value // Handle both success and error future.whenComplete((result, error) -> { if (error != null) { System.out.println("Error: " + error.getMessage()); } else { System.out.println("Result: " + result); } }); } // 4. Multiple Futures public void multipleFutures() throws Exception { List> futures = Arrays.asList( CompletableFuture.supplyAsync(() -> "Task 1"), CompletableFuture.supplyAsync(() -> "Task 2"), CompletableFuture.supplyAsync(() -> "Task 3") ); // Wait for all CompletableFuture all = CompletableFuture.allOf( futures.toArray(new CompletableFuture[0]) ); all.join(); // Wait for any CompletableFuture any = CompletableFuture.anyOf( futures.toArray(new CompletableFuture[0]) ); System.out.println("First completed: " + any.get()); } // 5. Timeout public void timeoutExample() throws Exception { CompletableFuture future = CompletableFuture.supplyAsync(() -> { sleep(2000); return "Slow result"; }); // Complete exceptionally if timeout future.orTimeout(1, TimeUnit.SECONDS) .thenAccept(System.out::println) .exceptionally(throwable -> { System.out.println("Timeout!"); return null; }); } private void sleep(int ms) { try { Thread.sleep(ms); } catch (InterruptedException e) {} } } JVM Internals Key Concepts java public class JVMInternals { // 1. Memory Management // Stack: Method calls, local variables (thread-local) // Heap: Objects (garbage collected) // Method Area: Class data, static variables // Program Counter Register: Current executing instruction // 2. Garbage Collection // Reference counting (not used in Java) // Mark and Sweep (used) // Generational GC: Young Gen, Old Gen, PermGen/Metaspace // 3. Memory Leak Example class MemoryLeakExample { private static final List leak = new ArrayList<>(); public void createLeak() { while (true) { // This will cause OutOfMemoryError leak.add(new byte[1024 * 1024]); // 1MB each } } } // 4. WeakReference Example (Prevent Leak) class WeakReferenceExample { private final Map> cache = new HashMap<>(); public void add(String key, Object value) { cache.put(key, new WeakReference<>(value)); } public Object get(String key) { WeakReference ref = cache.get(key); return ref != null ? ref.get() : null; } } // 5. JVM Options // -Xms: Initial heap size // -Xmx: Maximum heap size // -Xss: Thread stack size // -XX:+UseG1GC: Use G1 garbage collector // -XX:+PrintGCDetails: Print GC details // 6. Class Loading // Bootstrap ClassLoader: Core Java classes (rt.jar) // Extension ClassLoader: Java extensions // Application ClassLoader: Classpath classes // Custom ClassLoader: User-defined // 7. Just-In-Time Compilation // Interpreter: Executes bytecode // JIT Compiler: Compiles hot methods to native code // -XX:CompileThreshold: Number of method invocations before JIT // 8. Monitor/Lock Concept class MonitorExample { private int counter = 0; // Each object has a monitor public synchronized void increment() { counter++; // Acquires monitor lock } // Releases monitor lock // Using ReentrantLock (more flexibility) private final ReentrantLock lock = new ReentrantLock(); public void incrementWithLock() { lock.lock(); try { counter++; } finally { lock.unlock(); } } } } Design Patterns Common Patterns with Examples java // 1. Singleton Pattern class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } // 2. Factory Pattern interface Product { void operation(); } class ConcreteProductA implements Product { @Override public void operation() { System.out.println("Product A"); } } class ConcreteProductB implements Product { @Override public void operation() { System.out.println("Product B"); } } class ProductFactory { public Product createProduct(String type) { switch (type) { case "A": return new ConcreteProductA(); case "B": return new ConcreteProductB(); default: throw new IllegalArgumentException("Unknown type"); } } } // 3. Builder Pattern class Person { private final String name; private final int age; private final String email; private Person(Builder builder) { this.name = builder.name; this.age = builder.age; this.email = builder.email; } static class Builder { private String name; private int age; private String email; Builder name(String name) { this.name = name; return this; } Builder age(int age) { this.age = age; return this; } Builder email(String email) { this.email = email; return this; } Person build() { return new Person(this); } } } // 4. Observer Pattern interface Observer { void update(String message); } class ConcreteObserver implements Observer { private final String name; ConcreteObserver(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + " received: " + message); } } class Subject { private final List observers = new ArrayList<>(); void attach(Observer observer) { observers.add(observer); } void detach(Observer observer) { observers.remove(observer); } void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } } // 5. Strategy Pattern interface Strategy { int execute(int a, int b); } class AddStrategy implements Strategy { @Override public int execute(int a, int b) { return a + b; } } class MultiplyStrategy implements Strategy { @Override public int execute(int a, int b) { return a * b; } } class Context { private Strategy strategy; Context(Strategy strategy) { this.strategy = strategy; } int executeStrategy(int a, int b) { return strategy.execute(a, b); } } Low-Level Design Design a Parking Lot java public class ParkingLot { enum VehicleType { CAR, BIKE, TRUCK } enum SpotSize { SMALL, MEDIUM, LARGE } class Vehicle { String licensePlate; VehicleType type; SpotSize requiredSpotSize; } class ParkingSpot { int id; SpotSize size; boolean occupied; Vehicle vehicle; ParkingSpot(int id, SpotSize size) { this.id = id; this.size = size; } boolean park(Vehicle vehicle) { if (occupied) return false; this.vehicle = vehicle; this.occupied = true; return true; } void unpark() { this.vehicle = null; this.occupied = false; } } class Level { int floor; List spots; Level(int floor, int totalSpots) { this.floor = floor; spots = new ArrayList<>(); initializeSpots(totalSpots); } void initializeSpots(int total) { for (int i = 0; i < total; i++) { SpotSize size = i % 3 == 0 ? SpotSize.SMALL : i % 3 == 1 ? SpotSize.MEDIUM : SpotSize.LARGE; spots.add(new ParkingSpot(i, size)); } } ParkingSpot findAvailableSpot(VehicleType type) { SpotSize required = getRequiredSize(type); for (ParkingSpot spot : spots) { if (!spot.occupied && spot.size.ordinal() >= required.ordinal()) { return spot; } } return null; } SpotSize getRequiredSize(VehicleType type) { switch(type) { case BIKE: return SpotSize.SMALL; case CAR: return SpotSize.MEDIUM; case TRUCK: return SpotSize.LARGE; default: return SpotSize.LARGE; } } } List levels; int totalCapacity; public ParkingLot(int floors, int spotsPerFloor) { levels = new ArrayList<>(); totalCapacity = floors * spotsPerFloor; for (int i = 0; i < floors; i++) { levels.add(new Level(i, spotsPerFloor)); } } public boolean parkVehicle(Vehicle vehicle) { for (Level level : levels) { ParkingSpot spot = level.findAvailableSpot(vehicle.type); if (spot != null) { spot.park(vehicle); System.out.println("Vehicle parked at floor " + level.floor + " spot " + spot.id); return true; } } System.out.println("No available spots"); return false; } public boolean unparkVehicle(Vehicle vehicle) { for (Level level : levels) { for (ParkingSpot spot : level.spots) { if (spot.occupied && spot.vehicle.licensePlate.equals(vehicle.licensePlate)) { spot.unpark(); System.out.println("Vehicle unparked from floor " + level.floor + " spot " + spot.id); return true; } } } return false; } } System Design Design a URL Shortener java public class URLShortener { private static final String BASE_URL = "https://short.com/"; private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private static final int SHORT_URL_LENGTH = 6; private final Map urlToShort = new ConcurrentHashMap<>(); private final Map shortToUrl = new ConcurrentHashMap<>(); private final AtomicLong counter = new AtomicLong(1); // Method 1: Base62 Encoding public String shortenUrl(String longUrl) { if (urlToShort.containsKey(longUrl)) { return BASE_URL + urlToShort.get(longUrl); } long id = counter.getAndIncrement(); String shortCode = encodeBase62(id); urlToShort.put(longUrl, shortCode); shortToUrl.put(shortCode, longUrl); return BASE_URL + shortCode; } public String getOriginalUrl(String shortUrl) { String shortCode = shortUrl.replace(BASE_URL, ""); return shortToUrl.get(shortCode); } private String encodeBase62(long number) { StringBuilder sb = new StringBuilder(); while (number > 0) { sb.append(CHARACTERS.charAt((int) (number % 62))); number /= 62; } while (sb.length() < SHORT_URL_LENGTH) { sb.append('0'); // Pad with zeros } return sb.reverse().toString(); } private long decodeBase62(String code) { long result = 0; for (char c : code.toCharArray()) { result = result * 62 + CHARACTERS.indexOf(c); } return result; } // Method 2: MD5 Hashing public String shortenUrlMD5(String longUrl) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(longUrl.getBytes()); // Take first 6 characters of Base64 encoded digest String base64 = Base64.getUrlEncoder().withoutPadding().encodeToString(digest); String shortCode = base64.substring(0, SHORT_URL_LENGTH); urlToShort.put(longUrl, shortCode); shortToUrl.put(shortCode, longUrl); return BASE_URL + shortCode; } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } } Spring Boot Key Concepts and Examples java // 1. REST Controller @RestController @RequestMapping("/api/users") public class UserController { @Autowired private UserService userService; @GetMapping public List getAllUsers() { return userService.getAllUsers(); } @GetMapping("/{id}") public ResponseEntity getUserById(@PathVariable Long id) { return userService.getUserById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @PostMapping @ResponseStatus(HttpStatus.CREATED) public User createUser(@Valid @RequestBody User user) { return userService.createUser(user); } @PutMapping("/{id}") public User updateUser(@PathVariable Long id, @RequestBody User user) { return userService.updateUser(id, user); } @DeleteMapping("/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteUser(@PathVariable Long id) { userService.deleteUser(id); } } // 2. Service Layer @Service @Transactional public class UserService { @Autowired private UserRepository userRepository; public List getAllUsers() { return userRepository.findAll(); } public Optional getUserById(Long id) { return userRepository.findById(id); } public User createUser(User user) { return userRepository.save(user); } public User updateUser(Long id, User user) { return userRepository.findById(id) .map(existingUser -> { existingUser.setName(user.getName()); existingUser.setEmail(user.getEmail()); return userRepository.save(existingUser); }) .orElseThrow(() -> new EntityNotFoundException("User not found")); } public void deleteUser(Long id) { userRepository.deleteById(id); } } // 3. Repository @Repository public interface UserRepository extends JpaRepository { Optional findByEmail(String email); List findByNameContainingIgnoreCase(String name); @Query("SELECT u FROM User u WHERE u.age > :age") List findUsersOlderThan(@Param("age") int age); } // 4. Entity @Entity @Table(name = "users") @Data @NoArgsConstructor @AllArgsConstructor public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotBlank(message = "Name is required") @Size(min = 2, max = 50) private String name; @Email(message = "Invalid email format") @NotBlank(message = "Email is required") @Column(unique = true) private String email; @Min(value = 0, message = "Age must be positive") private int age; } // 5. Exception Handling @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(EntityNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleEntityNotFound(EntityNotFoundException ex) { return new ErrorResponse("NOT_FOUND", ex.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleValidationExceptions(MethodArgumentNotValidException ex) { Map errors = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach(error -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return new ErrorResponse("VALIDATION_ERROR", errors.toString()); } } // 6. Configuration @Configuration @EnableConfigurationProperties public class AppConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return mapper; } } Redis Spring Boot Redis Integration java // 1. Configuration @Configuration public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(); } @Bean public RedisTemplate redisTemplate() { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory()); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } @Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) .disableCachingNullValues(); return RedisCacheManager.builder(connectionFactory) .cacheDefaults(config) .build(); } } // 2. Service using Redis @Service public class RedisCacheService { @Autowired private RedisTemplate redisTemplate; private static final String USER_CACHE = "user:"; private static final Duration TTL = Duration.ofMinutes(30); public void cacheUser(String userId, User user) { redisTemplate.opsForValue().set(USER_CACHE + userId, user, TTL); } public User getUserFromCache(String userId) { return (User) redisTemplate.opsForValue().get(USER_CACHE + userId); } public void removeUserFromCache(String userId) { redisTemplate.delete(USER_CACHE + userId); } public void addToSet(String setKey, String value) { redisTemplate.opsForSet().add(setKey, value); } public Set getSetMembers(String setKey) { return redisTemplate.opsForSet().members(setKey); } public void addToList(String listKey, String value) { redisTemplate.opsForList().rightPush(listKey, value); } public List getList(String listKey, long start, long end) { return redisTemplate.opsForList().range(listKey, start, end); } } // 3. Using Cacheable annotation @Service @CacheConfig(cacheNames = "users") public class UserCacheService { @Cacheable(key = "#id") public User getUser(Long id) { // This method will be cached return userRepository.findById(id).orElse(null); } @CacheEvict(key = "#id") public void deleteUser(Long id) { userRepository.deleteById(id); } @CachePut(key = "#user.id") public User updateUser(User user) { return userRepository.save(user); } } // 4. Rate Limiter using Redis @Component public class RateLimiter { @Autowired private RedisTemplate redisTemplate; public boolean allowRequest(String userId, String action, int maxRequests, long windowSeconds) { String key = "ratelimit:" + userId + ":" + action; Long count = redisTemplate.opsForValue().increment(key); if (count == 1) { redisTemplate.expire(key, windowSeconds, TimeUnit.SECONDS); } return count <= maxRequests; } } Kafka Spring Boot Kafka Integration java // 1. Configuration @Configuration public class KafkaConfig { @Bean public ProducerFactory producerFactory() { Map props = new HashMap<>(); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); props.put(ProducerConfig.RETRIES_CONFIG, 3); props.put(ProducerConfig.ACKS_CONFIG, "all"); return new DefaultKafkaProducerFactory<>(props); } @Bean public KafkaTemplate kafkaTemplate() { return new KafkaTemplate<>(producerFactory()); } @Bean public ConsumerFactory consumerFactory() { Map props = new HashMap<>(); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); props.put(ConsumerConfig.GROUP_ID_CONFIG, "user-service"); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class); props.put(JsonDeserializer.TRUSTED_PACKAGES, "*"); props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); return new DefaultKafkaConsumerFactory<>(props); } @Bean public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(consumerFactory()); factory.setConcurrency(3); return factory; } } // 2. Producer Service @Service public class KafkaProducerService { @Autowired private KafkaTemplate kafkaTemplate; private static final String TOPIC = "user-events"; public void sendMessage(UserEvent event) { kafkaTemplate.send(TOPIC, event.getUserId(), event); System.out.println("Message sent: " + event); } public CompletableFuture> sendAsyncMessage(UserEvent event) { return kafkaTemplate.send(TOPIC, event.getUserId(), event) .completable() .whenComplete((result, error) -> { if (error != null) { System.err.println("Failed to send message: " + error.getMessage()); } else { System.out.println("Message sent successfully: " + result.getRecordMetadata()); } }); } } // 3. Consumer Service @Service public class KafkaConsumerService { @KafkaListener(topics = "user-events", groupId = "user-service") public void consumeEvent(UserEvent event) { System.out.println("Received event: " + event); processEvent(event); } private void processEvent(UserEvent event) { // Process the event switch (event.getType()) { case USER_CREATED: handleUserCreation(event); break; case USER_UPDATED: handleUserUpdate(event); break; case USER_DELETED: handleUserDeletion(event); break; } } } // 4. Event Class @AllArgsConstructor @NoArgsConstructor @Data public class UserEvent { private String userId; private String userEmail; private EventType type; private String data; enum EventType { USER_CREATED, USER_UPDATED, USER_DELETED } } // 5. Kafka Interceptor @Component public class CustomKafkaInterceptor implements ProducerInterceptor { @Override public ProducerRecord onSend(ProducerRecord record) { // Add headers or modify before sending record.headers().add("timestamp", System.currentTimeMillis()); return record; } @Override public void onAcknowledgement(RecordMetadata metadata, Exception exception) { // Handle acknowledgments if (exception != null) { System.err.println("Kafka error: " + exception.getMessage()); } } @Override public void close() { // Cleanup } @Override public void configure(Map configs) { // Configuration } } Kubernetes Key Concepts and Examples yaml # 1. Deployment apiVersion: apps/v1 kind: Deployment metadata: name: java-app labels: app: java-app spec: replicas: 3 selector: matchLabels: app: java-app strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: java-app spec: containers: - name: app image: java-app:latest ports: - containerPort: 8080 env: - name: SPRING_PROFILES_ACTIVE value: "prod" - name: DB_HOST valueFrom: configMapKeyRef: name: app-config key: db.host resources: requests: memory: "512Mi" cpu: "500m" limits: memory: "1Gi" cpu: "1000m" livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 20 periodSeconds: 5 --- # 2. Service apiVersion: v1 kind: Service metadata: name: java-app-service spec: selector: app: java-app ports: - port: 80 targetPort: 8080 type: LoadBalancer --- # 3. ConfigMap apiVersion: v1 kind: ConfigMap metadata: name: app-config data: db.host: "postgres-service" db.port: "5432" cache.host: "redis-service" --- # 4. Secret apiVersion: v1 kind: Secret metadata: name: app-secrets type: Opaque data: db.password: cGFzc3dvcmQxMjM= # base64 encoded --- # 5. Ingress apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: java-app-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: java-app-service port: number: 80 --- # 6. Horizontal Pod Autoscaler apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: java-app-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: java-app minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 Microservices Core Concepts and Patterns java // 1. Service Discovery @SpringBootApplication @EnableEurekaClient public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } } // 2. API Gateway @SpringBootApplication @EnableZuulProxy public class ApiGatewayApplication { public static void main(String[] args) { SpringApplication.run(ApiGatewayApplication.class, args); } } // 3. Feign Client @FeignClient(name = "user-service", url = "${user.service.url}") public interface UserServiceClient { @GetMapping("/users/{id}") User getUser(@PathVariable("id") Long id); @PostMapping("/users") User createUser(@RequestBody User user); } // 4. Circuit Breaker @Service public class OrderService { @Autowired private UserServiceClient userServiceClient; @Autowired private RetryTemplate retryTemplate; @CircuitBreaker(name = "userService", fallbackMethod = "getDefaultUser") public User getUserWithCircuitBreaker(Long userId) { return userServiceClient.getUser(userId); } public User getDefaultUser(Long userId, Throwable t) { return new User(userId, "Default User", "default@example.com"); } @Retryable(value = {RuntimeException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000)) public User getUserWithRetry(Long userId) { return userServiceClient.getUser(userId); } @Retryable(value = {RuntimeException.class}, maxAttempts = 3) @CircuitBreaker(name = "userService", fallbackMethod = "getDefaultUser") public User getUserWithBoth(Long userId) { return userServiceClient.getUser(userId); } } // 5. Distributed Tracing @Configuration public class TracingConfig { @Bean public Sampler defaultSampler() { return Sampler.ALWAYS_SAMPLE; } } // 6. Bulkhead Pattern @Service public class BulkheadService { @Bulkhead(name = "externalService", type = Bulkhead.Type.THREADPOOL, corePoolSize = 5, maxPoolSize = 10, queueCapacity = 10) @Fallback(fallbackMethod = "fallbackMethod") public String callExternalService() { // Call external service return "Success"; } private String fallbackMethod(Throwable t) { return "Fallback response"; } } // 7. Rate Limiter @Service public class RateLimitedService { @RateLimiter(name = "rateLimiter", fallbackMethod = "fallbackMethod") public String rateLimitedOperation() { // Operation that should be rate limited return "Operation successful"; } private String fallbackMethod(Throwable t) { return "Rate limit exceeded"; } } CodeSignal Medium Sample Problems java // 1. First Duplicate public int firstDuplicate(int[] a) { Set seen = new HashSet<>(); for (int num : a) { if (seen.contains(num)) return num; seen.add(num); } return -1; } // 2. Rotate Image public void rotate(int[][] matrix) { int n = matrix.length; // Transpose for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int temp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = temp; } } // Reverse each row for (int i = 0; i < n; i++) { for (int j = 0; j < n / 2; j++) { int temp = matrix[i][j]; matrix[i][j] = matrix[i][n - 1 - j]; matrix[i][n - 1 - j] = temp; } } } // 3. Maximum Subarray public int maxSubArray(int[] nums) { int maxEndingHere = nums[0]; int maxSoFar = nums[0]; for (int i = 1; i < nums.length; i++) { maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]); maxSoFar = Math.max(maxSoFar, maxEndingHere); } return maxSoFar; } // 4. Group Anagrams public List> groupAnagrams(String[] strs) { Map> map = new HashMap<>(); for (String str : strs) { char[] chars = str.toCharArray(); Arrays.sort(chars); String sorted = new String(chars); map.computeIfAbsent(sorted, k -> new ArrayList<>()).add(str); } return new ArrayList<>(map.values()); } CodeSignal Hard Advanced Problems java // 1. First Missing Positive public int firstMissingPositive(int[] nums) { int n = nums.length; // Place each number in its correct position for (int i = 0; i < n; i++) { while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) { swap(nums, i, nums[i] - 1); } } // Find first missing for (int i = 0; i < n; i++) { if (nums[i] != i + 1) { return i + 1; } } return n + 1; } // 2. Trapping Rain Water public int trap(int[] height) { int left = 0, right = height.length - 1; int leftMax = 0, rightMax = 0; int water = 0; while (left < right) { if (height[left] < height[right]) { if (height[left] >= leftMax) { leftMax = height[left]; } else { water += leftMax - height[left]; } left++; } else { if (height[right] >= rightMax) { rightMax = height[right]; } else { water += rightMax - height[right]; } right--; } } return water; } // 3. Longest Palindromic Substring public String longestPalindrome(String s) { if (s == null || s.length() < 2) return s; int start = 0, maxLen = 1; int n = s.length(); boolean[][] dp = new boolean[n][n]; for (int i = 0; i < n; i++) { dp[i][i] = true; if (i + 1 < n && s.charAt(i) == s.charAt(i + 1)) { dp[i][i + 1] = true; start = i; maxLen = 2; } } for (int len = 3; len <= n; len++) { for (int i = 0; i + len <= n; i++) { int j = i + len - 1; if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) { dp[i][j] = true; start = i; maxLen = len; } } } return s.substring(start, start + maxLen); } // 4. Regular Expression Matching public boolean isMatch(String s, String p) { int m = s.length(), n = p.length(); boolean[][] dp = new boolean[m + 1][n + 1]; dp[0][0] = true; // Handle patterns like a*, a*b*, a*b*c* for (int j = 2; j <= n; j++) { if (p.charAt(j - 1) == '*') { dp[0][j] = dp[0][j - 2]; } } for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') { dp[i][j] = dp[i - 1][j - 1]; } else if (p.charAt(j - 1) == '*') { dp[i][j] = dp[i][j - 2]; // Zero occurrence if (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') { dp[i][j] |= dp[i - 1][j]; // One or more occurrence } } } } return dp[m][n]; } Mock Interview Full Interview Simulation java // Mock Interview Session public class MockInterview { @Test void interviewSession() { // Part 1: Core Java assertAll("Core Java", () -> assertEquals(3, new ArrayList<>(Arrays.asList(1,2,3)).size()), () -> assertTrue(new HashMap<>().isEmpty()), () -> assertDoesNotThrow(() -> new ArrayList<>()) ); // Part 2: Collections List list = Arrays.asList(1, 2, 3, 4, 5); assertAll("Collections", () -> assertEquals(5, list.size()), () -> assertTrue(list.contains(3)), () -> assertFalse(list.contains(6)) ); // Part 3: Algorithm Problem - Two Sum int[] nums = {2, 7, 11, 15}; int target = 9; assertArrayEquals(new int[]{0, 1}, twoSum(nums, target)); // Part 4: System Design - Rate Limiter RateLimiter limiter = new RateLimiter(); for (int i = 0; i < 10; i++) { assertTrue(limiter.allowRequest("user1", "api", 10, 60)); } } // Two Sum implementation public int[] twoSum(int[] nums, int target) { Map map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int complement = target - nums[i]; if (map.containsKey(complement)) { return new int[]{map.get(complement), i}; } map.put(nums[i], i); } return new int[0]; } // Rate Limiter implementation class RateLimiter { private final Map requests = new ConcurrentHashMap<>(); public boolean allowRequest(String userId, String action, int maxRequests, long windowSeconds) { String key = userId + ":" + action; long current = System.currentTimeMillis(); long windowStart = current - windowSeconds * 1000; requests.entrySet().removeIf(e -> e.getValue() < windowStart); long count = requests.values().stream() .filter(t -> t >= windowStart) .count(); if (count < maxRequests) { requests.put(key + ":" + System.nanoTime(), current); return true; } return false; } } } Summary This comprehensive guide covers Java 26 interview topics across: Core Java: Collections, HashMap internals, equals/hashCode Data Structures: Lists, Sets, Maps, Queues Algorithms: Binary search, sorting, dynamic programming Concurrency: Thread-safe collections, CompletableFuture System Design: LRU Cache, URL Shortener, Parking Lot Spring Boot: REST APIs, caching, configuration Microservices: Service discovery, circuit breakers, tracing DevOps: Kubernetes, Kafka, Redis Practice Problems: CodeSignal, FAANG-level questions Key Tips for Success: Understand time/space complexity Practice coding without IDE Know common edge cases Be able to explain trade-offs Have working examples ready Understand real-world applications Additional Resources: LeetCode: Practice problems System Design Interview: An Insider's Guide Effective Java (3rd Edition) by Joshua Bloch Java Concurrency in Practice by Brian Goetz Good luck with your Java 26 interview! 🚀