Utilizing collections and streams
Collection choices
ArrayList offers fast random access; LinkedList is a Deque but slower for indexed access. HashSet has no order, LinkedHashSet preserves insertion order, and TreeSet keeps sorted order. HashMap, LinkedHashMap, and TreeMap follow the same ordering rules. List.of and Set.of are immutable; Arrays.asList is fixed-size but set() works. Iterator.remove is safe; modifying a collection during for-each throws ConcurrentModificationException.
Stream pipeline rules
A stream pipeline is a source, zero or more intermediate operations, and one terminal operation. Intermediate operations are lazy: filter, map, flatMap, distinct, sorted, limit, skip, peek. Terminal operations trigger execution: forEach, collect, reduce, count, anyMatch, findFirst. A stream cannot be reused after a terminal operation.
Worked example
var words = List.of("apple","avocado","banana","blueberry","cherry"); Map<Character,Long> m = words.stream().collect(Collectors.groupingBy(w -> w.charAt(0), TreeMap::new, Collectors.counting())); This groups by first letter into a sorted TreeMap; counting() produces Long values. flatMap would be needed if each word mapped to multiple values.
Traps
Collectors.toMap throws IllegalStateException on duplicate keys unless a merge function is supplied. sorted() without a comparator requires Comparable elements. peek() without a terminal operation does nothing. findFirst returns Optional; calling get() on an empty Optional throws NoSuchElementException.