The Collections framework
โ Report an issue with this lessonList<String> names = new ArrayList<>();
names.add("Ada");
Map<String, Integer> prices = new HashMap<>();
prices.put("html", 2999);
Set<String> uniqueTags = new HashSet<>();
uniqueTags.add("beginner");
Choose the right structure for the job: ArrayList for
ordered, indexable data; HashMap for fast key lookups;
HashSet when you only care whether something exists, not its
order. LinkedList, TreeMap, and
TreeSet exist for cases needing different ordering or
insertion guarantees.
Know the actual complexity of what you're calling.
ArrayList.get(i) is O(1) (backed by a real array), but
ArrayList.contains(x) and .remove(x) (by
value, not index) are O(n) -- they scan linearly. A
HashMap/HashSet gives O(1) average-case
lookup and insertion by hashing the key, but that guarantee quietly
degrades to O(n) if many keys collide -- which is exactly why a mutable
object used as a HashMap key is dangerous: if its
hashCode() depends on fields that change after insertion,
the map can no longer find it in the correct bucket, and lookups start
silently failing. TreeMap/TreeSet trade that
O(1) average case for guaranteed O(log n), backed by a red-black tree,
in exchange for keeping entries sorted by key.
Beyond the basics, Deque (usually backed by
ArrayDeque) covers both stack and queue behavior with
push/pop/offer/poll,
and is the recommended replacement for the legacy Stack
class, which is needlessly synchronized (and therefore slower) for
single-threaded use. PriorityQueue keeps its smallest
(or, with a custom Comparator, "highest priority") element
at the head, which makes it the natural structure for scheduling or
any "always process the most urgent item next" problem:
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
stack.push(2);
stack.pop(); // 2 -- last in, first out
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.addAll(List.of(5, 1, 3));
pq.poll(); // 1 -- smallest first
One gotcha worth internalizing early: most of these collections are
fail-fast. Modifying a list while iterating it directly with a
for-each loop throws ConcurrentModificationException
rather than silently producing a wrong result:
for (String name : names) {
if (name.equals("Ada")) {
names.remove(name); // throws ConcurrentModificationException
}
}
// use an Iterator directly and call it.remove(), or collect matches
// into a separate list and remove them afterward, instead
Also remember that none of ArrayList,
HashMap, or HashSet are thread-safe -- two
threads mutating one concurrently can corrupt its internal structure,
not just produce a race on the data. Reach for
ConcurrentHashMap, CopyOnWriteArrayList, or
external synchronization when a collection is shared across threads,
covered in more depth in the concurrency lesson.
Try it yourself
3 2999
Run your code and get it working before marking this lesson complete.
8 more lessons โ including Project: build a simple task scheduler โ and a final exam plus a certificate are waiting.
Unlock the full course โ $99.99