Java Collections are a foundational part of Java programming, enabling developers to manage and manipulate data effectively. But even experienced developers fall into traps when using List, Set, Map, or concurrent collections. These mistakes can cause memory leaks, race conditions, poor performance, or incorrect results in production.
This tutorial identifies common Java Collections mistakes, provides detailed explanations, and shows you how to fix or avoid them using modern Java practices from Java 8 to Java 21.
Core Concepts
Java Collections Framework provides interfaces like List, Set, Map, and their implementations like ArrayList, HashSet, and HashMap. It supports:
- Indexed collections (
List) - Unique elements (
Set) - Key-value mapping (
Map) - Thread-safe variants (
ConcurrentHashMap,CopyOnWriteArrayList) - Immutable versions (
List.of(),Map.of())
Top Common Mistakes
1. Using == Instead of .equals()
Set<String> set = new HashSet<>();
set.add("hello");
System.out.println(set.contains(new String("hello"))); // false if `==` used
✅ Use .equals() for logical comparison.
2. Modifying Collection During Iteration
for (String s : list) {
if (s.equals("delete")) list.remove(s); // ConcurrentModificationException
}
✅ Use Iterator.remove() or removeIf().
3. Choosing the Wrong Collection
- ❌ Using
Listwhen duplicates aren't allowed. - ✅ Use
Setfor uniqueness.
4. Not Using Generics
List list = new ArrayList(); // Raw type
✅ Use:
List<String> list = new ArrayList<>();
5. Ignoring HashCode/Equals Contracts
class Person { String name; }
Set<Person> set = new HashSet<>();
✅ Always override equals() and hashCode().
6. Using Legacy Types
- ❌
Vector,Hashtable - ✅ Use
ArrayList,ConcurrentHashMap
7. Not Initializing Capacity Properly
new HashMap<>(); // Default capacity 16
✅ Use:
new HashMap<>(expectedSize / 0.75f + 1);
Internal Implementation and Memory Model
ArrayListresizes by 50%—avoid frequent resizes by pre-sizing.HashMapswitches from linked lists to red-black trees on hash collisions.ConcurrentHashMapuses segmented locking for thread-safety.
Performance Considerations
| Operation | ArrayList | LinkedList | HashSet | TreeSet |
|---|---|---|---|---|
| Add | O(1)* | O(1) | O(1) | O(log n) |
| Remove | O(n) | O(1) | O(1) | O(log n) |
| Contains | O(n) | O(n) | O(1) | O(log n) |
Comparisons and Best Choices
- Need ordering? → Use
LinkedHashMap,TreeSet - Need thread safety? → Use
ConcurrentHashMap,CopyOnWriteArrayList - Need immutability? → Use
List.of(),Set.copyOf()
Version Differences in Java 8–21
- Java 8: Introduced
Stream,Optional,Collectors - Java 9:
List.of(),Map.of(), immutable collections - Java 10: Type inference with
var - Java 21: Performance tuning, structured concurrency
Functional Programming Pitfalls
- ❌ Using
map()whereflatMap()is needed - ❌ Using
stream().filter()on null collections (throws NPE) - ✅ Always check for null or use
Optional
Anti-patterns and Fixes
-
❌ Nested
ifchecks for null maps ✅ UseMap.computeIfAbsent() -
❌
ArrayListfor frequent removals at head ✅ UseLinkedListorDeque
Legacy Refactoring Tips
Before
Vector<String> list = new Vector<>();
After
List<String> list = new CopyOnWriteArrayList<>();
Best Practices Summary
- Use immutable collections for read-only data
- Use generics to prevent runtime
ClassCastException - Don’t expose modifiable collections from APIs
- Prefer
Streamsfor transformation logic - Use
Setfor uniqueness,Listfor order,Mapfor key-value mappings
📌 What's New in Java Versions?
- Java 8
Stream,Collectors.toList(),Optional, lambdas
- Java 9
List.of(),Map.of()– true immutability
- Java 10
varkeyword for type inference
- Java 21
- HashMap performance boosts, better tree binning
Conclusion and Key Takeaways
Mastering Java Collections means not just knowing how to use them—but understanding how to use them right. Avoiding common mistakes in choice, iteration, comparison, and thread-safety will make your Java code more robust, performant, and maintainable.
FAQ
1. Why is == not reliable for Strings?
It compares object references. Use .equals() for value comparison.
2. Can I add null to a HashSet?
Yes, one null is allowed.
3. What’s the default capacity of ArrayList?
10 (Java 8+)
4. Should I use Vector?
No. Use ArrayList with synchronization or CopyOnWriteArrayList.
5. Is HashMap ordered?
No. Use LinkedHashMap for insertion order.
6. What causes ConcurrentModificationException?
Modifying a collection during iteration.
7. How to avoid resizing in HashMap?
Initialize it with a proper capacity.
8. What’s the difference between List.of() and Arrays.asList()?
List.of() returns an immutable list; Arrays.asList() is fixed-size and modifiable.
9. Can I use stream() on null collections?
No. It throws NullPointerException.
10. What’s the difference between HashSet and TreeSet?
HashSet is unordered and faster; TreeSet is sorted and uses more memory.