A set stores distinct elements, but safe use depends on how membership and equality are implemented. Set implementations are specified to compare contents with equals(), unlike queues and other collection types for which content equality is not generally required. A List and a Set are never equal by specification, even when they contain the same elements. section 7.2
Preserve the equality contract when wrapping sets. Collections.unmodifiableCollection(set) does not itself implement Set, so it cannot delegate set-style equality without risking asymmetric results. Use Collections.unmodifiableSet() when callers need an unmodifiable set that still compares by contents as a set. section 7.2
Do not assume every Set handles null searches alike. HashSet can contain null, while factory-created sets such as Set.of() reject null elements and also reject contains(null). The declared Set type does not reveal that difference, so replacing a legacy unmodifiable set with Set.of() can turn a previously harmless lookup into a NullPointerException. section 8.3
Guard a nullable lookup
When the searched value may be null, make that case explicit: obj != null && platforms.contains(obj) This avoids calling contains(null) on a null-hostile set. Do not blindly modernize older unmodifiable set declarations to Set.of() unless callers and tests establish that null is never searched for. section 8.3
Treat objects stored in a hash-based set as stable with respect to equals() and hashCode(). If a mutable element changes after insertion, its hash code may change while it remains in the bucket selected by its old hash code. A later contains() or remove() lookup uses the new hash code, searches a different bucket, and may fail to find the same object. section 8.6
Set<List<String>> set = new HashSet<>();
List<String> list = new ArrayList<>();
set.add(list);
list.add("Value");
System.out.println(set.contains(list)); #1
The list is inserted while empty, then mutated. Its changed content changes its hash code, so contains(list) can search the wrong HashSet bucket and report false. section 8.6
Avoid membership failures by following these rules:
- Do not mutate an object after using it as a HashSet element when mutation can affect equals() or hashCode(). section 8.6
- Prefer immutable alternatives for date-and-time values when possible; mutable java.util.Date and Calendar can be changed after insertion. section 8.6
- Be especially cautious with StringBuilder: its content-based compareTo() conflicts with identity-based equals() and hashCode(), making modified HashSet elements unreliable. section 8.6
- Check nullable search inputs before calling contains() on sets whose implementation may be hidden behind the Set interface. section 8.3
Static analysis can report some suspicious equals() uses, but it cannot make collection equality or mutation safe automatically. Verify the concrete collection behavior, equality semantics, and whether stored objects can change after insertion. section 7.2 section 8.6














