Java Notes
Comprehensive Java Collections practice programs covering List, Set, Map, Queue operations with solutions, explanations, and time complexity analysis.
Program 1: Remove Duplicates While Preserving Order
Problem: Given a list with duplicates, remove duplicates while maintaining insertion order.
import java.util.*;
public class RemoveDuplicates {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(4, 2, 3, 2, 1, 4, 3, 5, 1);
// Method 1: LinkedHashSet preserves insertion order
List<Integer> unique = new ArrayList<>(new LinkedHashSet<>(numbers));
System.out.println("Unique: " + unique);
// Method 2: Stream with distinct()
List<Integer> unique2 = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("Unique (stream): " + unique2);
// Method 3: Manual with Set tracking
List<Integer> unique3 = new ArrayList<>();
Set<Integer> seen = new HashSet<>();
for (int num : numbers) {
if (seen.add(num)) { // add() returns true if element was new
unique3.add(num);
}
}
System.out.println("Unique (manual): " + unique3);
}
}Output:
| Unique | [4, 2, 3, 1, 5] |
| Unique (stream) | [4, 2, 3, 1, 5] |
| Unique (manual) | [4, 2, 3, 1, 5] |
Time Complexity: O(n) for all methods | Space: O(n) for the Set
Program 3: Sort a Map by Values
Problem: Sort a HashMap by its values in descending order.
import java.util.*;
import java.util.stream.*;
public class SortMapByValue {
public static void main(String[] args) {
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 92);
scores.put("Bob", 88);
scores.put("Charlie", 95);
scores.put("Diana", 91);
scores.put("Eve", 88);
// Method 1: Using Stream (Java 8+)
LinkedHashMap<String, Integer> sorted = scores.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
System.out.println("Sorted by value (desc): " + sorted);
// Method 2: Using List of entries
List<Map.Entry<String, Integer>> entries = new ArrayList<>(scores.entrySet());
entries.sort((a, b) -> b.getValue() - a.getValue());
System.out.println("Top scorers:");
entries.forEach(e -> System.out.println(" " + e.getKey() + ": " + e.getValue()));
}
}Output:
| Sorted by value (desc) | {Charlie=95, Alice=92, Diana=91, Bob=88, Eve=88} |
| Charlie | 95 |
| Alice | 92 |
| Diana | 91 |
| Bob | 88 |
| Eve | 88 |
Program 4: Find Intersection and Union of Two Lists
Intersection: [4, 5, 6] Union: [1, 2, 3, 4, 5, 6, 7, 8, 9] Difference (1-2): [1, 2, 3] Symmetric diff: [1, 2, 3, 7, 8, 9]
Program 5: LRU Cache Using LinkedHashMap
Problem: Implement a Least Recently Used (LRU) cache.
import java.util.*;
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true); // true = access-order
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity; // Remove oldest when over capacity
}
public static void main(String[] args) {
LRUCache<String, Integer> cache = new LRUCache<>(3);
cache.put("A", 1);
cache.put("B", 2);
cache.put("C", 3);
System.out.println(cache); // {A=1, B=2, C=3}
cache.get("A"); // Access A — moves to end
System.out.println(cache); // {B=2, C=3, A=1}
cache.put("D", 4); // B is evicted (least recently used)
System.out.println(cache); // {C=3, A=1, D=4}
cache.put("E", 5); // C is evicted
System.out.println(cache); // {A=1, D=4, E=5}
}
}{A=1, B=2, C=3}
{B=2, C=3, A=1}
{C=3, A=1, D=4}
{A=1, D=4, E=5}Time Complexity: O(1) for get and put operations.
Program 6: Find First Non-Repeated Character
First non-repeated: w First non-repeated (v2): w
Program 7: Group Objects by Property
Problem: Group a list of employees by department.
import java.util.*;
import java.util.stream.*;
record Employee(String name, String department, double salary) {}
public class GroupByDemo {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", "Engineering", 95000),
new Employee("Bob", "Marketing", 85000),
new Employee("Charlie", "Engineering", 92000),
new Employee("Diana", "Marketing", 88000),
new Employee("Eve", "Engineering", 98000),
new Employee("Frank", "HR", 75000)
);
// Group by department
Map<String, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::department));
byDept.forEach((dept, emps) -> {
System.out.println(dept + ": " + emps.size() + " employees");
emps.forEach(e -> System.out.println(" - " + e.name()));
});
// Average salary by department
Map<String, Double> avgSalary = employees.stream()
.collect(Collectors.groupingBy(
Employee::department,
Collectors.averagingDouble(Employee::salary)
));
System.out.println("\nAverage salaries: " + avgSalary);
// Highest paid per department
Map<String, Optional<Employee>> topEarner = employees.stream()
.collect(Collectors.groupingBy(
Employee::department,
Collectors.maxBy(Comparator.comparingDouble(Employee::salary))
));
topEarner.forEach((dept, emp) ->
System.out.println(dept + " top: " + emp.map(Employee::name).orElse("N/A"))
);
}
}Engineering: 2 employees
- Alice
- Charlie
Marketing: 1 employees
- Bob
Average salaries: {Engineering=77500.0, Marketing=60000.0}
Engineering top: Charlie
Marketing top: BobProgram 8: Implement Stack Using Queue
3 2 1
Program 9: Find K Most Frequent Elements
Top 2 frequent: [3, 1]
Time Complexity: O(n log k) — n for counting, log k for heap operations.
Program 10: Custom Object in HashSet/HashMap
Problem: Demonstrate proper equals/hashCode implementation.
Size: 2 Contains Alice: true
Program 11: Merge Two Sorted Lists
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Time Complexity: O(n + m) | Space: O(n + m)
Program 12: Producer-Consumer Using BlockingQueue
Produced: 0 Produced: 1 Consumed: 0 Produced: 2 Consumed: 1 Produced: 3 Consumed: 2 Produced: 4 Consumed: 3 Consumed: 4
Program 13: Anagram Grouping
import java.util.*;
import java.util.stream.*;
public class AnagramGrouping {
public static Map<String, List<String>> groupAnagrams(String[] words) {
return Arrays.stream(words)
.collect(Collectors.groupingBy(word -> {
char[] chars = word.toLowerCase().toCharArray();
Arrays.sort(chars);
return new String(chars);
}));
}
public static void main(String[] args) {
String[] words = {"eat", "tea", "tan", "ate", "nat", "bat"};
Map<String, List<String>> groups = groupAnagrams(words);
groups.forEach((key, anagrams) ->
System.out.println(anagrams));
}
}Output:
Program 14: Flatten Nested Collections
[1, 2, 3, 4, 5, 6, 7, 8, 9] [apple, banana, carrot, pea]
Program 15: Immutable Collection Patterns
Unmodifiable view: [A, B, C] After modifying original... Unmodifiable view: [A, B, C, D] Cannot modify immutable list!
Summary: Which Collection for Which Problem?
| Problem | Best Collection | Why |
|---|---|---|
| Remove duplicates | LinkedHashSet | O(1) contains + preserves order |
| Frequency counting | HashMap | O(1) get/put |
| Top K elements | PriorityQueue | O(n log k) |
| LRU Cache | LinkedHashMap (access-order) | O(1) + auto-eviction |
| Sorted unique elements | TreeSet | O(log n) + sorted iteration |
| FIFO processing | ArrayDeque | O(1) offer/poll |
| Thread-safe queue | ConcurrentLinkedQueue or BlockingQueue | Lock-free or blocking |
| Group by property | HashMap<Key, List<Value>> | O(1) bucket access |
| Bidirectional lookup | Two HashMaps | O(1) both directions |
Interview Questions
Q1: How do you remove duplicates from an ArrayList?
A: Convert to a LinkedHashSet (preserves order) or HashSet (no order guarantee): new ArrayList<>(new LinkedHashSet<>(list)). Alternatively, use Java 8 streams: list.stream().distinct().collect(Collectors.toList()).
Q2: How do you find the frequency of each element in a collection?
A: Use Collections.frequency(collection, element) for a single element, or build a frequency map: map.merge(element, 1, Integer::sum) in a loop, or use streams with Collectors.groupingBy(Function.identity(), Collectors.counting()).
Q3: How do you sort a Map by its values?
A: Convert entries to a list and sort: entries.sort(Map.Entry.comparingByValue()). Or use streams: map.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(...).
Q4: What is the difference between Collections.unmodifiableList() and List.of()?
A: unmodifiableList() creates a read-only VIEW of the original list — changes to the original reflect through the view. List.of() (Java 9+) creates a truly IMMUTABLE list — no connection to any mutable source.
Q5: How do you implement an LRU Cache using collections?
A: Use LinkedHashMap with access-order enabled (constructor parameter true) and override removeEldestEntry() to return true when size exceeds capacity.
Q6: What is the most efficient way to find the intersection of two sets?
A: Use retainAll(): create a copy of set1, then call copy.retainAll(set2). Time complexity is O(n) for HashSets.
Q7: How do you merge two sorted lists efficiently?
A: Use a merge algorithm (like merge sort's merge step) with two pointers, comparing elements and adding the smaller one. Time complexity: O(n + m).
Q8: How do you find the top K frequent elements in a collection?
A: Build a frequency map, then use a PriorityQueue (min-heap of size K) or sort the entries by frequency and take the top K. Stream approach: group, sort by count descending, limit K.
Q9: How do you make an ArrayList thread-safe?
A: Three options: (1) Collections.synchronizedList(new ArrayList<>()), (2) Use CopyOnWriteArrayList for read-heavy scenarios, (3) External synchronization with explicit locks.
Q10: How do you flatten a list of lists into a single list?
A: Use flatMap with streams: listOfLists.stream().flatMap(Collection::stream).collect(Collectors.toList()). Or iteratively: loop through each inner list and addAll to result.
Q11: How do you implement a Stack using Queues?
A: Use two queues. For push: add to queue1. For pop: transfer all but last element from queue1 to queue2, remove last element, swap queues. This makes push O(1) and pop O(n), or vice versa.
Q12: What is the Producer-Consumer pattern with collections?
A: Use a BlockingQueue (like ArrayBlockingQueue) — producers call put() (blocks if full) and consumers call take() (blocks if empty). The queue handles all synchronization internally.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Collections Practice Programs.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, collections, framework, programs
Related Java Master Course Topics