# Java 26 Interview Questions & Answers — Comprehensive Guide

> A complete, well-structured Q&A guide covering collections, concurrency, JVM internals, design patterns, system design, Spring Boot, Redis, Kafka, Kubernetes, microservices, and coding problems — aligned with Java 26 (LTS).

---

## Table of Contents

1. [Collections Framework](#1-collections-framework)
   - [ArrayList vs LinkedList](#arraylist-vs-linkedlist)
   - [Vector vs ArrayList](#vector-vs-arraylist)
2. [HashMap Internals](#2-hashmap-internals)
   - [LinkedHashMap](#linkedhashmap)
   - [TreeMap](#treemap)
   - [Hash Collision](#hash-collision)
   - [equals() vs hashCode()](#equals-vs-hashcode)
3. [Set Implementations](#3-set-implementations)
   - [HashSet vs LinkedHashSet vs TreeSet](#hashset-vs-linkedhashset-vs-treeset)
4. [Queue & Deque](#4-queue--deque)
   - [PriorityQueue](#priorityqueue)
   - [ArrayDeque](#arraydeque)
   - [Queue vs Deque](#queue-vs-deque)
5. [Comparable vs Comparator](#5-comparable-vs-comparator)
   - [Comparable](#comparable)
   - [Comparator](#comparator)
   - [Collections.sort()](#collectionssort)
   - [Binary Search](#binary-search)
6. [Advanced Collections](#6-advanced-collections)
   - [Reverse HashMap](#reverse-hashmap)
   - [Merge Maps](#merge-maps)
   - [Frequency Counter](#frequency-counter)
   - [Remove Duplicates](#remove-duplicates)
7. [Coding Problems](#7-coding-problems)
   - [Top-K Elements](#top-k-elements)
   - [LRU Cache (3 Implementations)](#lru-cache-3-implementations)
   - [WeakHashMap](#weakhashmap)
   - [IdentityHashMap](#identityhashmap)
   - [EnumMap & EnumSet](#enummap--enumset)
8. [Concurrent Collections](#8-concurrent-collections)
   - [CopyOnWriteArrayList](#copyonwritearraylist)
   - [ConcurrentHashMap](#concurrenthashmap)
   - [BlockingQueue](#blockingqueue)
9. [Interview MCQs](#9-interview-mcqs)
10. [JUnit 5 Tests](#10-junit-5-tests)
11. [Real Interview Questions from FAANG/Banks](#11-real-interview-questions-from-faangbanks)
12. [Immutable Collections](#12-immutable-collections)
13. [JUnit Tests — Comprehensive Test Suite](#13-junit-tests--comprehensive-test-suite)
14. [Collections, Arrays, Strings](#14-collections-arrays-strings)
15. [HashMap & Set Advanced](#15-hashmap--set-advanced)
16. [Streams](#16-streams)
17. [Recursion & Backtracking](#17-recursion--backtracking)
18. [Linked List](#18-linked-list)
19. [Stack & Queue](#19-stack--queue)
20. [Trees](#20-trees)
21. [Graphs](#21-graphs)
22. [Dynamic Programming](#22-dynamic-programming)
23. [Concurrency](#23-concurrency)
24. [CompletableFuture](#24-completablefuture)
25. [JVM Internals](#25-jvm-internals)
26. [Design Patterns](#26-design-patterns)
27. [Low-Level Design](#27-low-level-design)
28. [System Design](#28-system-design)
29. [Spring Boot](#29-spring-boot)
30. [Redis](#30-redis)
31. [Kafka](#31-kafka)
32. [Kubernetes](#32-kubernetes)
33. [Microservices](#33-microservices)
34. [CodeSignal Medium](#34-codesignal-medium)
35. [CodeSignal Hard](#35-codesignal-hard)
36. [Mock Interview](#36-mock-interview)
37. [Summary](#37-summary)

---

## 1. 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<String> arrayList = new ArrayList<>();
arrayList.add("A");  // O(1)
arrayList.get(0);    // O(1)

// LinkedList - Best for frequent modifications at ends
List<String> 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<String> vector = new Vector<>();
vector.add("A");  // Synchronized method

// ArrayList - Not thread-safe but faster
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("A");  // Not synchronized
```

---

## 2. HashMap Internals

### HashMap Internal Structure

**Java 8+ Implementation:**
- Array of `Node<K,V>` (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<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;  // For linked list
    TreeNode<K,V> 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<String, Integer> map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);

// Iteration maintains insertion order
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "=" + entry.getValue());
}
// Output: A=1, B=2, C=3

// LRU Cache with access-order
LinkedHashMap<String, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<String, String> 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<String, Integer> 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<String, Integer> 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<Employee, String> map = new HashMap<>();
map.put(e1, "Value");
System.out.println(map.get(e2));  // "Value" - works due to proper equals/hashCode
```

---

## 3. 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<String> hashSet = new HashSet<>();
hashSet.add("B");
hashSet.add("A");
hashSet.add("C");
// Order: unpredictable

// LinkedHashSet - Maintains insertion order
Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("B");
linkedSet.add("A");
linkedSet.add("C");
// Order: B, A, C

// TreeSet - Sorted
Set<String> treeSet = new TreeSet<>();
treeSet.add("B");
treeSet.add("A");
treeSet.add("C");
// Order: A, B, C
```

---

## 4. 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<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(1);
pq.offer(2);
System.out.println(pq.poll());  // 1

// Max-heap with custom comparator
PriorityQueue<Integer> 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<Task> 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<String> stack = new ArrayDeque<>();
stack.push("A");
stack.push("B");
System.out.println(stack.pop());  // B

// As Queue (FIFO)
Deque<String> queue = new ArrayDeque<>();
queue.offer("A");
queue.offer("B");
System.out.println(queue.poll());  // A

// Operations at both ends
Deque<Integer> 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<String> 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<String> 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
```

---

## 5. 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<Student> {
    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<Student> 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<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return s1.name.compareTo(s2.name);
    }
}

class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return Integer.compare(s1.age, s2.age);
    }
}

// Usage with lambda
List<Student> 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<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int idx = Collections.binarySearch(list, 3);  // 2

// With custom comparator
List<String> 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;
}
```

---

## 6. Advanced Collections

### Reverse HashMap

```java
// Reverse Map: invert key-value pairs
public <K, V> Map<V, K> reverseMap(Map<K, V> original) {
    Map<V, K> reversed = new HashMap<>();
    for (Map.Entry<K, V> entry : original.entrySet()) {
        reversed.put(entry.getValue(), entry.getKey());
    }
    return reversed;
}

// With duplicate values handling
public <K, V> Map<V, List<K>> reverseMapWithDuplicates(Map<K, V> original) {
    Map<V, List<K>> reversed = new HashMap<>();
    for (Map.Entry<K, V> entry : original.entrySet()) {
        reversed.computeIfAbsent(entry.getValue(), k -> new ArrayList<>())
                .add(entry.getKey());
    }
    return reversed;
}

// Java 8 Streams approach
Map<String, Integer> map = Map.of("A", 1, "B", 2, "C", 3);
Map<Integer, String> reversed = map.entrySet().stream()
    .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
```

### Merge Maps

```java
// Simple merge
Map<String, Integer> map1 = new HashMap<>();
map1.put("A", 1);
map1.put("B", 2);

Map<String, Integer> map2 = new HashMap<>();
map2.put("B", 3);
map2.put("C", 4);

// Method 1: putAll (overwrites)
Map<String, Integer> merged = new HashMap<>(map1);
merged.putAll(map2);  // B becomes 3

// Method 2: merge with conflict resolution
Map<String, Integer> merged2 = new HashMap<>(map1);
for (Map.Entry<String, Integer> 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<String, Integer> 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 <T> Map<T, Long> frequencyCounter(List<T> list) {
    return list.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

// Manual approach
public <T> Map<T, Integer> countFrequency(List<T> list) {
    Map<T, Integer> 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<Character, Long> 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<String, Long> 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<Integer> removeDuplicates(List<Integer> 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<String> removeDuplicatesPreserveOrder(List<String> list) {
    Set<String> 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<Person> removeDuplicatesByField(List<Person> people) {
    Set<String> seenNames = new HashSet<>();
    return people.stream()
        .filter(p -> seenNames.add(p.getName()))
        .collect(Collectors.toList());
}
```

---

## 7. Coding Problems

### Top-K Elements

```java
// Using PriorityQueue (Min-Heap for K largest)
public List<Integer> topK(int[] nums, int k) {
    PriorityQueue<Integer> 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<Integer> topKFrequent(int[] nums, int k) {
    // 1. Count frequencies
    Map<Integer, Integer> freq = new HashMap<>();
    for (int num : nums) {
        freq.put(num, freq.getOrDefault(num, 0) + 1);
    }

    // 2. Use min-heap to keep top K
    PriorityQueue<Map.Entry<Integer, Integer>> heap =
        new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue));

    for (Map.Entry<Integer, Integer> entry : freq.entrySet()) {
        heap.offer(entry);
        if (heap.size() > k) {
            heap.poll();
        }
    }

    // 3. Extract results
    List<Integer> 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<Integer> topKFrequentBucket(int[] nums, int k) {
    Map<Integer, Integer> freq = new HashMap<>();
    for (int num : nums) {
        freq.put(num, freq.getOrDefault(num, 0) + 1);
    }

    // Bucket sort by frequency
    List<Integer>[] buckets = new List[nums.length + 1];
    for (Map.Entry<Integer, Integer> entry : freq.entrySet()) {
        int f = entry.getValue();
        if (buckets[f] == null) {
            buckets[f] = new ArrayList<>();
        }
        buckets[f].add(entry.getKey());
    }

    List<Integer> 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<K, V> extends LinkedHashMap<K, V> {
    private final int capacity;

    public LRUCache1(int capacity) {
        super(capacity, 0.75f, true);  // accessOrder = true
        this.capacity = capacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > capacity;
    }
}
```

#### Implementation 2: Using Custom Doubly LinkedList + HashMap

```java
class LRUCache2<K, V> {
    private final int capacity;
    private final Map<K, Node<K, V>> map;
    private final DoublyLinkedList<K, V> list;

    static class Node<K, V> {
        K key;
        V value;
        Node<K, V> prev;
        Node<K, V> next;

        Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }

    static class DoublyLinkedList<K, V> {
        Node<K, V> head;
        Node<K, V> tail;

        void addToFront(Node<K, V> node) {
            if (head == null) {
                head = tail = node;
            } else {
                node.next = head;
                head.prev = node;
                head = node;
            }
        }

        void moveToFront(Node<K, V> node) {
            if (node == head) return;
            remove(node);
            addToFront(node);
        }

        void remove(Node<K, V> 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<K, V> removeLast() {
            if (tail == null) return null;
            Node<K, V> 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<K, V> node = map.get(key);
        if (node == null) return null;
        list.moveToFront(node);
        return node.value;
    }

    public void put(K key, V value) {
        Node<K, V> node = map.get(key);
        if (node != null) {
            node.value = value;
            list.moveToFront(node);
        } else {
            Node<K, V> newNode = new Node<>(key, value);
            map.put(key, newNode);
            list.addToFront(newNode);
            if (map.size() > capacity) {
                Node<K, V> 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<K, V> {
    private final int capacity;
    private final ConcurrentHashMap<K, Node<K, V>> map;
    private final DoublyLinkedList<K, V> 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<K, V> 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<K, V> node = map.get(key);
            if (node != null) {
                node.value = value;
                list.moveToFront(node);
            } else {
                Node<K, V> newNode = new Node<>(key, value);
                map.put(key, newNode);
                list.addToFront(newNode);
                if (map.size() > capacity) {
                    Node<K, V> removed = list.removeLast();
                    map.remove(removed.key);
                }
            }
        } finally {
            lock.writeLock().unlock();
        }
    }
}
```

### WeakHashMap

```java
// WeakHashMap - entries removed when keys are garbage collected
WeakHashMap<String, String> 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<String, Object> 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<String, String> 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<Day, String> 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<Status> activeStatuses = EnumSet.of(Status.ACTIVE, Status.PENDING);
EnumSet<Status> allStatuses = EnumSet.allOf(Status.class);
EnumSet<Status> noneStatuses = EnumSet.noneOf(Status.class);

// Use case: Filtering
public boolean isValidStatus(Status status) {
    Set<Status> valid = EnumSet.of(Status.ACTIVE, Status.PENDING);
    return valid.contains(status);
}
```

---

## 8. Concurrent Collections

### CopyOnWriteArrayList

```java
// Thread-safe, optimized for read-heavy scenarios
CopyOnWriteArrayList<String> 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<String, Integer> 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<K,V> (buckets)
// - CAS operations for node manipulation
// - Tree bins for high collision scenarios
```

### BlockingQueue

```java
// BlockingQueue implementations
BlockingQueue<String> arrayQueue = new ArrayBlockingQueue<>(10);
BlockingQueue<String> linkedQueue = new LinkedBlockingQueue<>();
BlockingQueue<String> priorityQueue = new PriorityBlockingQueue<>();
BlockingQueue<String> syncQueue = new SynchronousQueue<>();
BlockingQueue<String> transferQueue = new LinkedTransferQueue<>();

// Producer-Consumer example
class Producer implements Runnable {
    private BlockingQueue<String> queue;

    public Producer(BlockingQueue<String> 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<String> queue;

    public Consumer(BlockingQueue<String> 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<String> queue = new ArrayBlockingQueue<>(5);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new Producer(queue));
executor.execute(new Consumer(queue));
```

---

## 9. 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.

---

## 10. 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<Integer> arrayList = new ArrayList<>();
        List<Integer> 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<String, Integer> 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<Integer> 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<String, Integer> 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<Integer> 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<String> 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<String, Integer> map = Map.of("A", 1, "B", 2, "C", 3);
        assertTrue(map.containsKey(key));
    }
}
```

---

## 11. Real Interview Questions from FAANG/Banks

### 1. Design a thread-safe LRU Cache (Google)

```java
class ThreadSafeLRUCache<K, V> {
    private final int capacity;
    private final ConcurrentHashMap<K, Node<K, V>> cache;
    private final DoublyLinkedList<K, V> 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<K, V> 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<Integer> findAnagrams(String s, String p) {
    List<Integer> result = new ArrayList<>();
    if (s.length() < p.length()) return result;

    Map<Character, Integer> pCount = new HashMap<>();
    Map<Character, Integer> 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<String> queue = new LinkedList<>(Arrays.asList(data.split(SEP)));
        return deserializeHelper(queue);
    }

    private TreeNode deserializeHelper(Queue<String> 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<Integer> maxHeap;  // Lower half
    private PriorityQueue<Integer> 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<String> wordList) {
    Set<String> dict = new HashSet<>(wordList);
    if (!dict.contains(endWord)) return 0;

    Queue<String> 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<Integer, Integer> count = new HashMap<>();
    for (int num : nums) {
        count.put(num, count.getOrDefault(num, 0) + 1);
    }

    // Use min-heap of size k
    PriorityQueue<Integer> 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<Integer> 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<Integer, Node> 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);
            }
        }
    }
}
```

---

## 12. Immutable Collections

```java
import java.util.*;

public class ImmutableCollectionsDemo {
    public static void main(String[] args) {
        // Java 9+ immutable collections
        List<String> immutableList = List.of("A", "B", "C");
        Set<Integer> immutableSet = Set.of(1, 2, 3);
        Map<String, Integer> immutableMap = Map.of("A", 1, "B", 2);

        // Custom immutable class
        final class ImmutablePerson {
            private final String name;
            private final int age;
            private final List<String> hobbies;

            public ImmutablePerson(String name, int age, List<String> 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<String> getHobbies() {
                return new ArrayList<>(hobbies);  // Return copy
            }
        }

        // Using Collections.unmodifiableXXX()
        List<String> modifiable = new ArrayList<>(Arrays.asList("A", "B"));
        List<String> 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<String> trulyImmutable = List.copyOf(modifiable);
    }
}
```

---

## 13. 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<String> 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<String> 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<String, String> 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<String, Integer> map) {
            map.put("A", 1);
            map.put("B", 2);
            assertEquals(1, map.get("A"));
            assertEquals(2, map.size());
        }

        static Stream<Map<String, Integer>> 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<Integer> 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<Integer> 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<Integer> 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())
            );
        }
    }
}
```

---

## 14. Collections, Arrays, Strings

### Common Utility Methods

```java
public class CollectionUtils {

    // Collections methods
    public static void collectionsExamples() {
        List<Integer> 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<Integer> unmodifiable = Collections.unmodifiableList(list);
        List<Integer> 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);
    }
}
```

---

## 15. HashMap & Set Advanced

### Custom HashMap Implementation

```java
class CustomHashMap<K, V> {
    private static class Entry<K, V> {
        K key;
        V value;
        Entry<K, V> next;

        Entry(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }

    private Entry<K, V>[] 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<K, V> 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<K, V> 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<K, V> 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<K, V>[] oldBuckets = buckets;
        buckets = new Entry[oldBuckets.length * 2];
        size = 0;

        for (Entry<K, V> entry : oldBuckets) {
            while (entry != null) {
                put(entry.key, entry.value);
                entry = entry.next;
            }
        }
    }
}
```

### Custom HashSet Implementation

```java
class CustomHashSet<E> {
    private static final Object PRESENT = new Object();
    private final CustomHashMap<E, Object> 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;
    }
}
```

---

## 16. Streams

### Java 8 Stream Examples

```java
public class StreamExamples {

    // Filtering and Mapping
    public void filteringExamples() {
        List<String> list = Arrays.asList("apple", "banana", "cherry", "date");

        // Filter
        List<String> filtered = list.stream()
            .filter(s -> s.length() > 5)
            .collect(Collectors.toList());  // ["banana", "cherry"]

        // Map
        List<Integer> lengths = list.stream()
            .map(String::length)
            .collect(Collectors.toList());  // [5, 6, 6, 4]

        // Filter and map combined
        List<Integer> longWordsLength = list.stream()
            .filter(s -> s.length() > 5)
            .map(String::length)
            .collect(Collectors.toList());  // [6, 6]
    }

    // Reduction Operations
    public void reductionExamples() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // Sum
        int sum = numbers.stream()
            .reduce(0, Integer::sum);  // 15

        // Max
        Optional<Integer> max = numbers.stream()
            .reduce(Integer::max);  // 5

        // Min
        Optional<Integer> min = numbers.stream()
            .reduce(Integer::min);  // 1

        // Product
        int product = numbers.stream()
            .reduce(1, (a, b) -> a * b);  // 120
    }

    // Grouping
    public void groupingExamples() {
        List<Person> people = Arrays.asList(
            new Person("Alice", 30, "Engineer"),
            new Person("Bob", 25, "Designer"),
            new Person("Charlie", 35, "Engineer")
        );

        // Group by profession
        Map<String, List<Person>> byProfession = people.stream()
            .collect(Collectors.groupingBy(Person::getProfession));

        // Count by profession
        Map<String, Long> countByProfession = people.stream()
            .collect(Collectors.groupingBy(Person::getProfession, Collectors.counting()));

        // Average age by profession
        Map<String, Double> avgAgeByProfession = people.stream()
            .collect(Collectors.groupingBy(Person::getProfession,
                     Collectors.averagingInt(Person::getAge)));
    }

    // Advanced Operations
    public void advancedExamples() {
        List<String> words = Arrays.asList("Hello", "World", "Java");

        // FlatMap - flatten nested structures
        List<Character> chars = words.stream()
            .flatMap(s -> s.chars().mapToObj(c -> (char) c))
            .collect(Collectors.toList());

        // Peek - for debugging
        List<Integer> processed = words.stream()
            .map(String::length)
            .peek(System.out::println)
            .collect(Collectors.toList());

        // Distinct
        List<Integer> duplicates = Arrays.asList(1, 2, 2, 3, 3, 3);
        List<Integer> unique = duplicates.stream()
            .distinct()
            .collect(Collectors.toList());  // [1, 2, 3]

        // Sorted
        List<Integer> sorted = duplicates.stream()
            .sorted()
            .collect(Collectors.toList());  // [1, 2, 2, 3, 3, 3]

        // Limit and Skip
        List<Integer> firstThree = numbers.stream()
            .limit(3)
            .collect(Collectors.toList());

        List<Integer> skipFirst = numbers.stream()
            .skip(2)
            .collect(Collectors.toList());
    }

    static class Person {
        String name;
        int age;
        String profession;
        // Constructor, getters
    }
}
```

---

## 17. Recursion & Backtracking

### Classic Problems

```java
public class RecursionExamples {

    // 1. N-Queens Problem
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> 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<List<String>> 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<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        subsetsHelper(nums, 0, new ArrayList<>(), result);
        return result;
    }

    private void subsetsHelper(int[] nums, int start, List<Integer> current,
                              List<List<Integer>> 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<List<Integer>> permutations(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        permutationsHelper(nums, 0, result);
        return result;
    }

    private void permutationsHelper(int[] nums, int start, List<List<Integer>> 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);
        }
    }
}
```

---

## 18. 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;
    }
}
```

---

## 19. Stack & Queue

### Implementation and Problems

```java
public class StackQueueProblems {

    // 1. Min Stack
    class MinStack {
        private Stack<Integer> stack;
        private Stack<Integer> 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<Integer> s1;
        private Stack<Integer> 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<Integer> q1;
        private Queue<Integer> 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<Integer> 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<Character> stack = new Stack<>();
        Map<Character, Character> 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();
    }
}
```

---

## 20. 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<Integer> inorder(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        inorderHelper(root, result);
        return result;
    }

    private void inorderHelper(TreeNode node, List<Integer> result) {
        if (node == null) return;
        inorderHelper(node.left, result);
        result.add(node.val);
        inorderHelper(node.right, result);
    }

    // 2. Level Order Traversal
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> 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);
    }
}
```

---

## 21. Graphs

### Graph Algorithms

```java
public class GraphAlgorithms {

    // 1. BFS
    public void bfs(Map<Integer, List<Integer>> graph, int start) {
        Set<Integer> visited = new HashSet<>();
        Queue<Integer> 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<Integer, List<Integer>> graph, int start) {
        Set<Integer> visited = new HashSet<>();
        dfsHelper(graph, start, visited);
    }

    private void dfsHelper(Map<Integer, List<Integer>> graph, int node, Set<Integer> 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<Integer, List<Integer>> graph) {
        Set<Integer> visited = new HashSet<>();
        Set<Integer> recursionStack = new HashSet<>();

        for (int node : graph.keySet()) {
            if (hasCycleHelper(graph, node, visited, recursionStack)) {
                return true;
            }
        }
        return false;
    }

    private boolean hasCycleHelper(Map<Integer, List<Integer>> graph, int node,
                                   Set<Integer> visited, Set<Integer> 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<Integer> topologicalSort(Map<Integer, List<Integer>> graph, int vertices) {
        int[] indegree = new int[vertices];
        for (List<Integer> neighbors : graph.values()) {
            for (int neighbor : neighbors) {
                indegree[neighbor]++;
            }
        }

        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < vertices; i++) {
            if (indegree[i] == 0) {
                queue.offer(i);
            }
        }

        List<Integer> 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<Integer, Integer> dijkstra(Map<Integer, List<Edge>> graph, int start) {
        Map<Integer, Integer> distances = new HashMap<>();
        PriorityQueue<Node> 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;
        }
    }
}
```

---

## 22. 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];
    }
}
```

---

## 23. 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<Integer> 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<Runnable> 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");
        }
    }
}
```

---

## 24. CompletableFuture

### Asynchronous Programming

```java
public class CompletableFutureExamples {

    // 1. Basic Usage
    public void basicExample() throws Exception {
        CompletableFuture<String> 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<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");

        // Combine both results
        CompletableFuture<String> combined = future1.thenCombine(future2,
            (s1, s2) -> s1 + " " + s2);
        System.out.println(combined.get());  // Hello World

        // Chain multiple futures
        CompletableFuture<String> chained = future1.thenCompose(s ->
            CompletableFuture.supplyAsync(() -> s + " " + "World"));
        System.out.println(chained.get());  // Hello World
    }

    // 3. Error Handling
    public void errorHandling() throws Exception {
        CompletableFuture<String> 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<CompletableFuture<String>> futures = Arrays.asList(
            CompletableFuture.supplyAsync(() -> "Task 1"),
            CompletableFuture.supplyAsync(() -> "Task 2"),
            CompletableFuture.supplyAsync(() -> "Task 3")
        );

        // Wait for all
        CompletableFuture<Void> all = CompletableFuture.allOf(
            futures.toArray(new CompletableFuture[0])
        );
        all.join();

        // Wait for any
        CompletableFuture<Object> any = CompletableFuture.anyOf(
            futures.toArray(new CompletableFuture[0])
        );
        System.out.println("First completed: " + any.get());
    }

    // 5. Timeout
    public void timeoutExample() throws Exception {
        CompletableFuture<String> 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) {}
    }
}
```

---

## 25. 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<byte[]> 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<String, WeakReference<Object>> cache = new HashMap<>();

        public void add(String key, Object value) {
            cache.put(key, new WeakReference<>(value));
        }

        public Object get(String key) {
            WeakReference<Object> 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();
            }
        }
    }
}
```

---

## 26. 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<Observer> 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);
    }
}
```

---

## 27. 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<ParkingSpot> 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<Level> 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;
    }
}
```

---

## 28. 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<String, String> urlToShort = new ConcurrentHashMap<>();
    private final Map<String, String> 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);
        }
    }
}
```

---

## 29. Spring Boot

### Key Concepts and Examples

```java
// 1. REST Controller
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> 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<User> getAllUsers() {
        return userRepository.findAll();
    }

    public Optional<User> 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<User, Long> {

    Optional<User> findByEmail(String email);

    List<User> findByNameContainingIgnoreCase(String name);

    @Query("SELECT u FROM User u WHERE u.age > :age")
    List<User> 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<String, String> 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;
    }
}
```

---

## 30. Redis

### Spring Boot Redis Integration

```java
// 1. Configuration
@Configuration
public class RedisConfig {

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> 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<String, Object> 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<Object> getSetMembers(String setKey) {
        return redisTemplate.opsForSet().members(setKey);
    }

    public void addToList(String listKey, String value) {
        redisTemplate.opsForList().rightPush(listKey, value);
    }

    public List<Object> 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<String, String> 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;
    }
}
```

---

## 31. Kafka

### Spring Boot Kafka Integration

```java
// 1. Configuration
@Configuration
public class KafkaConfig {

    @Bean
    public ProducerFactory<String, Object> producerFactory() {
        Map<String, Object> 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<String, Object> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }

    @Bean
    public ConsumerFactory<String, Object> consumerFactory() {
        Map<String, Object> 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<String, Object> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, Object> factory =
            new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        factory.setConcurrency(3);
        return factory;
    }
}

// 2. Producer Service
@Service
public class KafkaProducerService {

    @Autowired
    private KafkaTemplate<String, Object> 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<SendResult<String, Object>> 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<String, Object> {

    @Override
    public ProducerRecord<String, Object> onSend(ProducerRecord<String, Object> 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<String, ?> configs) {
        // Configuration
    }
}
```

---

## 32. 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
```

---

## 33. 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";
    }
}
```

---

## 34. CodeSignal Medium

### Sample Problems

```java
// 1. First Duplicate
public int firstDuplicate(int[] a) {
    Set<Integer> 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<List<String>> groupAnagrams(String[] strs) {
    Map<String, List<String>> 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());
}
```

---

## 35. 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];
}
```

---

## 36. 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<Integer> 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<Integer, Integer> 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<String, Long> 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;
        }
    }
}
```

---

## 37. 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!
