Binary SemaphoreBinary Semaphore/learn
mentorshiptopicsroadmapsnotebooks
sign in
CC++JavaPythonJavaScriptTypeScriptGoDSAOperating SystemsNetworksDatabasesSystem DesignTheory and CompilersMaths for CSFrontendBackend and APIsSecurityCloud and DevOpsTestingAIGit and the ShellDebuggingInterviews and Viva
Java
  • memory-and-gc
  • concurrency-traps
  • collections-in-anger
  • equals-and-hashcode
  • interview-questions
  • viva-defence

© 2026 Binary Semaphore

discord

Java

Collections in anger

Which one to reach for, what it costs, and what happens when you mutate while iterating.

The collections framework is the part of Java you will use every single day, and the part most people learn by copying whatever was already in the file.

Most of what goes wrong comes from three questions nobody asked: what does this cost, what does it guarantee about order, and can I change it.

ArrayList against LinkedList

The textbook answer is that ArrayList is slow to insert in the middle and LinkedList is fast. The textbook answer is nearly always wrong in practice.

ArrayList is a contiguous array. Reading by index is one memory access, and walking it is close to the fastest thing a computer does, because the whole region is already in cache.

LinkedList is a chain of separately allocated nodes. Getting to element 500 means following 500 pointers to 500 places that are probably not near each other. It has a better complexity class for middle insertion and it still usually loses, because you spend all your time waiting on memory rather than doing work.

Use ArrayList. The exceptions are narrow enough that if you are in one, you will know.

HashMap, and the resize you did not think about

A HashMap puts entries in buckets chosen by hash. When it gets too full it allocates a bigger table and rehashes everything into it.

That means two things. Building a large map without sizing it does that work repeatedly, so pass an initial capacity when you know roughly how many entries are coming. And iteration order is not insertion order, is not sorted, and is not stable across versions. If you rely on it, you have written a bug that will surface during a demo.

When you want insertion order, that is LinkedHashMap. When you want sorted order, that is TreeMap, and it costs you log n per operation to get it.

Modifying while iterating



More on this is coming, and asking moves it up the list.

Want this written up?

Sign in and tell us. We write the ones people actually ask for, and asking takes one click.

Sign in to ask

Or sit with someone on it instead of waiting for us to write it.

What we have

Nothing yet, and no canonical source worth pointing at.

Book an hour on this
for
(String
s
:
list) {
if (s.isEmpty()) list.remove(s);
}

This throws ConcurrentModificationException, and the name misleads everyone: it has nothing to do with threads. One thread is enough. The iterator noticed the list changed underneath it.

Use list.removeIf(String::isEmpty), or iterate with an explicit Iterator and call it.remove(). Both express the intent better than the loop did.

Three ways to get a list, three different objects

Arrays.asList(a, b) is a fixed-size view over an array. You may set, you may not add. Surprising exactly once.

List.of(a, b) is genuinely immutable. Every mutation throws. It also rejects nulls, which catches more bugs than it causes.

new ArrayList<>(List.of(a, b)) is a real, mutable list.

Reaching for the wrong one produces an UnsupportedOperationException at runtime from a line that looks completely reasonable.

Choosing, in one pass

Ordered and indexed, which is most of the time: ArrayList.

Uniqueness matters: HashSet, or LinkedHashSet when you also want the order you added things in.

Keys to values: HashMap, unless you need sorted keys or insertion order.

Shared between threads: ConcurrentHashMap, and remember that safety per operation is not safety across two of them.

The thing that catches people

If you put an object in a HashSet or use it as a HashMap key and then

mutate a field that its hashCode depends on, it is lost. The collection looks in the bucket the old hash pointed at and finds nothing. The object is still in the map and containsKey says no.

Keys should be immutable, and that is the practical reason why, not a style preference.

Under questioning

Expect: ArrayList versus LinkedList and be ready to argue against the textbook, how HashMap works internally, what happens on collision, and why ConcurrentModificationException is not about concurrency.