We can use a HashSet<MyClass> or TreeSet<MyClass> to deduplicate our custom class objects. For this, our class must override two functions:

  1. hashCode(): where to store the object
  2. equals(Object o): deduplication

We need both of these to work together correctly: if two objects are .equals(), then they must have the same .hashCode().

1. Override hashCode()

@Override
public int hashCode() {
	// We can either compose them from the attributes own hashCodes
	return string1.hashCode() + Objects.hash(myInt);
	// Or use Objects.hash() if order matters
    return Objects.hash(field1, field2, field3);
}

Idempotence and Commutativity

Note that if field1 and field2 are commutative in your custom class, you cannot use Objects.hash() as Objects.hash(n1, n2) != Objects.hash(n2, n2). Therefore you have to use Objects.hash(n1) + Objects.hash(n2).

2. Override .equals(Object o)

@Override
public boolean equals(Object obj) {
    // Step 1: Reference equality check (optimization)
    if (this == obj) return true;
    
    // Step 2: Null and class check
    if (obj == null || getClass() != obj.getClass()) return false;
    
    // Step 3: Cast to your class type
    YourClass other = (YourClass) obj;
    
    // Step 4: Compare significant fields
    return field1.equals(other.field1) &&
           primitiveField == other.primitiveField &&
           Objects.equals(nullableField, other.nullableField);
}

You of course have to change the comparison logic to match the desired behaviour.