Choosing the right collection type and using it correctly is essential for readable, performant Java code.

Choosing the Right Collection

Need Recommended
Ordered list with fast random access ArrayList
Frequent insert/delete at ends or middle LinkedList
Unique elements, no order needed HashSet
Unique elements, sorted order TreeSet
Key-value lookup, no order HashMap
Key-value lookup, sorted by key TreeMap
Thread-safe queue ConcurrentLinkedQueue, ArrayBlockingQueue
Fixed-size ordered list List.of() (immutable)
Enum keys/values EnumMap, EnumSet

Prefer Interfaces in APIs

  // Good — flexible for callers
public void process(List<String> items) { }

// Avoid — locks callers into ArrayList
public void process(ArrayList<String> items) { }
  

Declare variables and parameters as List, Set, Map, Queue — instantiate with concrete types.

Immutability

Use immutable collections when data should not change:

  List<String> fixed = List.of("a", "b", "c");
Set<Integer> ids = Set.of(1, 2, 3);
Map<String, Integer> scores = Map.of("Alice", 95, "Bob", 87);

// Java 9+ copy constructors
List<String> copy = List.copyOf(mutableList);
  

Immutable collections throw UnsupportedOperationException on modification attempts.

Initial Capacity

Pre-size collections when the expected size is known:

  List<String> list = new ArrayList<>(1000);
Map<String, User> map = new HashMap<>(1000);
  

HashMap default load factor is 0.75 — for 1000 entries, use new HashMap<>(1334).

Iteration

  // Enhanced for-loop — preferred for simple iteration
for (String item : list) {
    System.out.println(item);
}

// Iterator — safe removal during iteration
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().startsWith("X")) {
        it.remove();
    }
}

// forEach with lambda
list.forEach(System.out::println);
  

Do not modify a collection while iterating with enhanced for-loop — use Iterator.remove() or removeIf().

Null Handling

Collection Allows null keys/elements?
ArrayList Yes (elements)
HashMap Yes (one null key, null values)
TreeMap No (null keys throw NPE)
HashSet Yes (one null element)
ConcurrentHashMap No

Be consistent — avoid mixing null and non-null in the same collection.

Performance Tips

  • ArrayList — O(1) get/set, O(n) insert/remove in middle
  • LinkedList — O(1) insert/remove at ends, O(n) random access
  • HashMap — O(1) average get/put; use good hashCode()/equals()
  • TreeMap/TreeSet — O(log n) operations; use when sorted order is needed
  • Prefer enhanced for-loop or streams over indexed loops for readability

Common Mistakes

  // ❌ Modifying list while iterating
for (String s : list) {
    if (s.isEmpty()) list.remove(s); // ConcurrentModificationException
}

// ✅ Use removeIf
list.removeIf(String::isEmpty);

// ❌ Using raw types
List list = new ArrayList(); // Avoid

// ✅ Use generics
List<String> list = new ArrayList<>();
  

Best Practices Summary

  • Program to interfaces, not implementations
  • Use immutable collections for constants and return values
  • Choose the simplest collection that meets your requirements
  • Pre-size collections when size is predictable
  • Use generics everywhere — never raw types