java 47 lines · 8 steps

Diffing two collections with set operations

A small immutable value type computes what was added, removed, and unchanged between two collections using plain set algebra.

Explained by highlit
1import java.util.HashSet;
2import java.util.Set;
3 
4public final class CollectionDiff<T> {
5 
6 private final Set<T> added;
7 private final Set<T> removed;
8 private final Set<T> unchanged;
9 
10 private CollectionDiff(Set<T> added, Set<T> removed, Set<T> unchanged) {
11 this.added = added;
12 this.removed = removed;
13 this.unchanged = unchanged;
14 }
15 
16 public static <T> CollectionDiff<T> between(Collection<? extends T> before, Collection<? extends T> after) {
17 Set<T> source = new HashSet<>(before);
18 Set<T> target = new HashSet<>(after);
19 
20 Set<T> added = new HashSet<>(target);
21 added.removeAll(source);
22 
23 Set<T> removed = new HashSet<>(source);
24 removed.removeAll(target);
25 
26 Set<T> unchanged = new HashSet<>(source);
27 unchanged.retainAll(target);
28 
29 return new CollectionDiff<>(added, removed, unchanged);
30 }
31 
32 public Set<T> added() {
33 return Set.copyOf(added);
34 }
35 
36 public Set<T> removed() {
37 return Set.copyOf(removed);
38 }
39 
40 public Set<T> unchanged() {
41 return Set.copyOf(unchanged);
42 }
43 
44 public boolean hasChanges() {
45 return !added.isEmpty() || !removed.isEmpty();
46 }
47}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Set difference and intersection give you added, removed, and unchanged in three cheap operations.
  2. 2A private constructor plus a static factory keeps construction logic in one clear entry point.
  3. 3Copying sets on the way out prevents callers from mutating internal state.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Diffing two collections with set operations — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code