Collections: ArrayList, HashSet and HashMap in practice
Which collection to pick, how HashMap put and get behave, and why removing inside a for-each loop throws an exception.
Almost every Java screening includes a collections question, and the first month on the job is spent moving data in and out of lists and maps. You do not need the whole framework. You need three classes, their rules, and the handful of traps that cause runtime exceptions.
Choosing the right one
ArrayList: ordered, allows duplicates, fast index access. Default choice for a list.HashSet: no duplicates, no guaranteed order, fastcontains. Use it to remove repeats or test membership.HashMap: key to value, one value per key, no guaranteed order. UseTreeMapwhen you need sorted keys orLinkedHashMapto keep insertion order.
Declare the variable with the interface type (List, Set, Map) so you can swap the implementation later.
List<String> names = new ArrayList<>();
names.add("Ravi");
names.add("Asha");
names.add("Ravi");
System.out.println(names.size()); // 3
Set<String> unique = new HashSet<>(names);
System.out.println(unique.size()); // 2
Map<String, Integer> stock = new HashMap<>();
stock.put("pen", 10);
stock.put("pen", 25); // replaces the old value
System.out.println(stock.get("pen")); // 25
System.out.println(stock.get("ink")); // null
System.out.println(stock.getOrDefault("ink", 0)); // 0Counting with a map
The counting loop is the most common map exercise in tests and in real code.
Map<String, Integer> counts = new HashMap<>();
for (String n : names) {
counts.put(n, counts.getOrDefault(n, 0) + 1);
}
System.out.println(counts.get("Ravi")); // 2Keys rely on hashCode() and equals(). If you use your own class as a key or in a HashSet, override both together, or two equal objects will be stored twice.
Removing elements safely
Changing a list while a for-each loop is walking it throws ConcurrentModificationException. Use removeIf or an explicit Iterator instead.
List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4));
for (Integer n : nums) {
if (n % 2 == 0) nums.remove(n); // throws ConcurrentModificationException
}
nums = new ArrayList<>(List.of(1, 2, 3, 4));
nums.removeIf(n -> n % 2 == 0);
System.out.println(nums); // [1, 3]
List<Integer> ids = new ArrayList<>(List.of(5, 10, 15));
ids.remove(Integer.valueOf(10)); // removes the value 10
ids.remove(0); // removes index 0
System.out.println(ids); // [15]Common mistakes and a practice habit
- Calling
remove(10)on aList<Integer>and expecting the value 10 to go; the int overload removes index 10. - Trying to
addto a list made withList.of(). It is unmodifiable and throwsUnsupportedOperationException. Wrap it innew ArrayList<>(...)first. - Calling
geton a map and using the result without a null check. - Expecting
HashMaporHashSetto print in the order you added items.
Practice habit: Write the counting loop, the duplicate removal and the safe removeIf from memory once a day for a week, compiling each time. These three snippets cover most collection questions you will meet in a test or a code review.
More in Programming