How to Get the Difference Between Two Sets in Java


How can we obtain the difference (or symmetric difference) between two sets in Java?

The difference of two sets refers to all elements in one set but not the other.

The symmetric difference of two sets refers to all elements in either set but not in both.

Suppose we have two instances of a HashSet, both populated with objects of some class T.

Set<T> set1 = new HashSet<>();
Set<T> set2 = new HashSet<>();

1. Using Guava

If we’re using Guava, we can use Sets.difference() to obtain all elements in set1 but not in set2.

SetView<T> diff = Sets.difference(set1, set2);

We can also obtain the symmetric difference of the two sets using Sets.symmetricDifference(). This will return all elements in either set1 or set2 but not in both.

SetView<T> symDiff = Sets.symmetricDifference(set1, set2);

In both solutions above, set1 and set2 are not modified.

The resulting SetView is a Set that we can make immutable (using .immutableCopy()) or copy into another set (using .copyInto(set3)).

Note that the result of these two functions will be undefined if set1 and set2 are sets based on different equivalence relations (i.e. HashSet, TreeSet, IdentityHashMap.keySet()).

2. Using Apache Commons Collection

If we have the Apache Commons Collections available, we can use SetUtils.difference().

This will return all elements in set1 but not in set2.

SetUtils.difference(set1, set2);

If we want the symmetric difference (all elements in either set1 or set2 but not both), then we can use CollectionUtils.disjunction().

CollectionUtils.disjunction(set1, set2);

3. Using Set.removeAll()

We can also use Set.removeAll() to get the intersection of two sets.

After running the code below, set1 will contain all elements originally in set1 but not in set2.

set1.removeAll(set2);

If we do not want to mutate either of the sets, we can create a copy.

Set<T> diff = new HashSet<>(set1)
diff.removeAll(set2);

To obtain the symmetric difference, we can do the following:

Set<T> symDiff = new HashSet<T>(set1);
symDiff.addAll(set2);
Set<T> temp = new HashSet<T>(set1);
temp.retainAll(set2);
symDiff.removeAll(temp);

4. Using Set.removeIf()

We can use Set.removeIf() if we’re running Java 8 or above.

Similarly, if we can mutate the set, we can call Set.removeIf() directly on the set.

set1.removeIf(set2::contains);

Otherwise, we can first create a copy, then run the function.

Set<T> diff = new HashSet<T>(set1);
diff.removeIf(set2::contains);

Obtaining the symmetric difference looks the same as well:

Set<T> symDiff = new HashSet<T>(set1);
symDiff.addAll(set2);
Set<T> temp = new HashSet<T>(set1);
temp.retainAll(set2);
symDiff.removeIf(temp::contains);