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
List
when duplicates aren't allowed. - ✅ Use
Set
for 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
ArrayList
resizes by 50%—avoid frequent resizes by pre-sizing.HashMap
switches from linked lists to red-black trees on hash collisions.ConcurrentHashMap
uses 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
if
checks for null maps ✅ UseMap.computeIfAbsent()
-
❌
ArrayList
for frequent removals at head ✅ UseLinkedList
orDeque
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
Streams
for transformation logic - Use
Set
for uniqueness,List
for order,Map
for 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
var
keyword 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.