Java collections
List, Set and Map — which implementation to pick, and why the interface you declare matters more than the class you use.
Choosing a collection
| Interface | Common implementation | Behaviour |
|---|---|---|
List | ArrayList | Ordered, index access, fast append |
List | LinkedList | Fast insert/remove near ends, slow random access |
Set | HashSet | No duplicates, no order guarantee |
Set | LinkedHashSet | No duplicates, insertion order |
Set | TreeSet | No duplicates, sorted |
Map | HashMap | Key/value, fast lookup, unordered |
Map | TreeMap | Keys kept sorted |
Queue | ArrayDeque | Fast add/remove at both ends |
💡
Declare the interface, not the implementation:
List<String> names = new ArrayList<>(); — swapping the implementation later then touches one line.Using them
var names = new ArrayList<String>();
names.add("Ada");
names.add("Grace");
names.add(0, "Alan");
var unique = new LinkedHashSet<>(names);
var byId = new HashMap<Integer, String>();
byId.put(1, "Ada");
byId.getOrDefault(99, "unknown");
byId.computeIfAbsent(2, k -> "created");
names.sort(Comparator.naturalOrder());for (String n : names) System.out.println(n);
names.forEach(System.out::println);
var adults = people.stream()
.filter(p -> p.age() >= 18)
.map(Person::name)
.toList();equals and hashCode
Hash-based collections find entries by hashCode() and confirm with equals(). Override one without the other and lookups silently fail — the object lands in the wrong bucket.
public record User(int id, String email) {} // equals/hashCode generated
// mutating a key after insertion makes an entry unreachable
var key = new MutableKey("a");
map.put(key, 1);
key.setName("b");
map.get(key); // null - its hash changed⚠️
Never mutate an object used as a map key or set member. Records are a good default precisely because they are immutable and generate correct
equals/hashCode.FAQ
ArrayList or array?
Arrays have fixed length and are fine for hot numeric loops.
ArrayList grows, works with generics and the collections API — the normal choice.How do I iterate and remove safely?
Use
iterator.remove() or list.removeIf(predicate). Removing inside a for-each loop throws ConcurrentModificationException.Related
Java types and variables Exceptions and try-with-resources
Last refreshed 2026-09-17.