Avoid List.contains In Loop
ID |
java.loop_list_contains |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Efficiency |
Language |
Java |
Tags |
efficiency |
Description
Reports calls to contains on a List-shaped receiver (List, ArrayList, LinkedList, Vector, Stack, ArrayDeque) made from inside the body or condition of a loop.
Rationale
List.contains is O(n) — it scans the backing array or linked cells comparing each element with equals. Used inside an outer loop of size m, the combined work becomes O(n·m), and if n and m are both user-sized, the runtime blows up visibly under load. Sets are the natural fix: HashSet.contains is amortised O(1), and building a Set view of the lookup list once — before the loop — turns the hot path back into linear time.
// Bad — allowList.contains runs for every candidate
for (String c : candidates) {
if (allowList.contains(c)) {
process(c);
}
}
// Good — build the lookup set once
Set<String> allow = new HashSet<>(allowList);
for (String c : candidates) {
if (allow.contains(c)) {
process(c);
}
}
Remediation
Wrap the lookup collection in a HashSet (or another Set implementation) before the loop, and use the set for membership tests. When the list is small and fixed (a handful of constant values), also consider Set.of(…) as a static final field.