HashSet
A Set based on hashing
HashSet<E> is a common Set implementation.
It uses hashing to determine quickly whether an element is stored in the set.
The standard HashSet implementation uses a HashMap internally,
but what matters to a set user is the rule: there are elements only, with no separate values associated with keys.
Set<String> emails = new HashSet<>();
emails.add("a@example.com");
emails.add("b@example.com");
emails.add("a@example.com");
System.out.println(emails.size()); // 2
On average, add(), contains(), and
remove() run in close to constant time.
That makes HashSet especially useful for frequent “have I already seen this?” checks.
Where uniqueness comes from
When an object is added, HashSet uses its
hashCode() and equals().
If the set finds an equal object, the new instance is not added.
Set<String> codes = new HashSet<>();
codes.add(new String("JAVA"));
codes.add(new String("JAVA"));
System.out.println(codes.size()); // 1
This is a good example of uniqueness not being about whether two references point to the same object. What matters is logical equality as defined by the class.
The same risks with mutable objects
If an object changes in a way that changes its hash or equality while it is inside a HashSet,
a contains() check may stop finding it correctly.
So set elements, just like HashMap keys, should be stable from the point of view of equality.