Skip to main content

📚 Java Core Collections: List, Set, Map

Overview 🎯

Java Collections Framework provides a unified architecture for storing and manipulating groups of objects. The three main interfaces - List, Set, and Map - form the backbone of data collection handling in Java applications.

Real-World Analogy

Think of Java Collections like different types of containers:

  • List: A todo list where order matters and items can repeat
  • Set: A basket of unique fruits where duplicates are automatically removed
  • Map: A phone book where each name (key) is associated with a phone number (value)

Key Concepts 🔑

Core Interfaces

List Interface

  • Ordered collection (sequence)
  • Elements are indexed (zero-based)
  • Allows duplicate elements
  • Main implementations: ArrayList, LinkedList, Vector

Set Interface

  • Unordered collection of unique elements
  • No duplicate elements allowed
  • Main implementations: HashSet, TreeSet, LinkedHashSet

Map Interface

  • Key-value pairs collection
  • Keys must be unique
  • Values can be duplicated
  • Main implementations: HashMap, TreeMap, LinkedHashMap

Implementation Examples 💻

Basic Usage Examples

import java.util.*;

public class CollectionsExample {
public void demonstrateCollections() {
// List example
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Apple"); // Duplicates allowed

// Set example
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // Duplicate not added

// Map example
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);
}
}

Advanced Operations

import java.util.*;
import java.util.stream.*;

public class AdvancedCollections {
public void advancedOperations() {
// List operations
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> doubled = numbers.stream()
.map(n -> n * 2)
.collect(Collectors.toList());

// Set operations
Set<String> set1 = new HashSet<>(Arrays.asList("A", "B", "C"));
Set<String> set2 = new HashSet<>(Arrays.asList("B", "C", "D"));

// Union
Set<String> union = new HashSet<>(set1);
union.addAll(set2);

// Intersection
Set<String> intersection = new HashSet<>(set1);
intersection.retainAll(set2);

// Map operations
Map<String, Integer> scores = new HashMap<>();
scores.computeIfAbsent("Player1", k -> 0);
scores.merge("Player1", 10, Integer::sum);
}
}

Best Practices 🌟

Choice of Implementation

  1. List Implementation

    • Use ArrayList for random access and fixed-size lists
    • Use LinkedList for frequent insertions/deletions
    • Avoid Vector unless thread safety is required
  2. Set Implementation

    • Use HashSet for best performance
    • Use TreeSet when ordered iteration is needed
    • Use LinkedHashSet for insertion-order iteration
  3. Map Implementation

    • Use HashMap for general purpose
    • Use TreeMap for sorted keys
    • Use LinkedHashMap for predictable iteration order

Performance Considerations

  • Initial Capacity
// Good: Set initial capacity
List<String> list = new ArrayList<>(10000);

// Bad: Let it resize multiple times
List<String> list = new ArrayList<>();
  • Collection Sizing
// Good: Use correct collection size
Map<String, String> map = new HashMap<>(expectedSize / 0.75f + 1);

// Bad: Default size with many elements
Map<String, String> map = new HashMap<>();

Common Pitfalls 🚨

  1. Concurrent Modification
// Wrong:
for (String item : list) {
if (condition) list.remove(item); // ConcurrentModificationException
}

// Correct:
list.removeIf(item -> condition);
  1. Null Handling
// Wrong:
map.put("key", null); // May throw NullPointerException in some implementations

// Correct:
map.putIfAbsent("key", "defaultValue");

Use Cases 🎯

1. Shopping Cart (List)

public class ShoppingCart {
private List<Item> items = new ArrayList<>();

public void addItem(Item item) {
items.add(item);
}

public double getTotal() {
return items.stream()
.mapToDouble(Item::getPrice)
.sum();
}
}

2. User Session Management (Set)

public class SessionManager {
private Set<String> activeSessions = new HashSet<>();

public void addSession(String sessionId) {
activeSessions.add(sessionId);
}

public boolean isSessionActive(String sessionId) {
return activeSessions.contains(sessionId);
}
}

3. Cache Implementation (Map)

public class SimpleCache<K, V> {
private Map<K, V> cache = new HashMap<>();

public V get(K key, Supplier<V> compute) {
return cache.computeIfAbsent(key, k -> compute.get());
}
}

Deep Dive Topics 🔍

Thread Safety

  1. Synchronized Collections
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
  1. Concurrent Collections
import java.util.concurrent.*;

ConcurrentHashMap<String, String> concurrentMap = new ConcurrentHashMap<>();
CopyOnWriteArrayList<String> copyOnWriteList = new CopyOnWriteArrayList<>();
CopyOnWriteArraySet<String> copyOnWriteSet = new CopyOnWriteArraySet<>();

Performance Optimization

  1. Bulk Operations
// Good: Bulk add
list.addAll(collection);

// Bad: Individual adds
for (Item item : collection) {
list.add(item);
}
  1. Using the Right Collection
// Good: Using Set for lookups
Set<String> lookupSet = new HashSet<>(items);
boolean contains = lookupSet.contains(item); // O(1)

// Bad: Using List for lookups
List<String> lookupList = new ArrayList<>(items);
boolean contains = lookupList.contains(item); // O(n)

Additional Resources 📚

Official Documentation

Tools

FAQs ❓

Q: When should I use ArrayList vs LinkedList?

A: Use ArrayList for random access and when the size doesn't change much. Use LinkedList for frequent insertions/deletions in the middle of the list.

Q: How do I make my collections thread-safe?

A: Use Collections.synchronizedXXX() methods or concurrent collections from java.util.concurrent package.

Q: What's the difference between HashMap and Hashtable?

A: Hashtable is thread-safe but obsolete. Use ConcurrentHashMap for thread-safe operations or HashMap for single-threaded scenarios.

Q: How do I sort a Collection?

A: Use Collections.sort() for Lists or TreeSet/TreeMap for automatically sorted collections. You can also use stream().sorted() for custom sorting.

Q: What's the best way to iterate over a Map?

A: Use the entrySet() method with a for-each loop or Map.forEach() for the most efficient iteration:

map.forEach((key, value) -> {
// Process key and value
});