Atom Feed SITE FEED   ADD TO GOOGLE READER

Coding in the small with Google Collections: Sets.union, intersection and difference

Part 16 in a Series.

The traditional approach to unions is to first create a new Set, and then to addAll using each component set. You can use a similar approach to do differences and intersections.

Before:

  private static final ImmutableSet<String> LEGAL_PARAMETERS;
static {
Set<String> tmp = new HashSet<String>();
tmp.addAll(REQUIRED_PARAMETERS);
tmp.addAll(OPTIONAL_PARAMETERS);
LEGAL_PARAMETERS = ImmutableSet.copyOf(tmp);
}

public void login(Map<String, String> params) {
if (!LEGAL_PARAMETERS.containsAll(params.keySet())) {
Set<String> unrecognized = new HashSet<String>(params.keySet());
unrecognized.removeAll(LEGAL_PARAMETERS);
throw new IllegalArgumentException("Unrecognized parameters: "
+ unrecognized);
}

if (!params.keySet().containsAll(REQUIRED_PARAMETERS)) {
Set<String> missing = new HashSet<String>(REQUIRED_PARAMETERS);
missing.removeAll(params.keySet());
throw new IllegalArgumentException("Missing parameters: " + missing);
}

...
}
Google Collections has methods that do set arithmetic in a single line.

After:

  private static final ImmutableSet<String> LEGAL_PARAMETERS
= Sets.union(REQUIRED_PARAMETERS, OPTIONAL_PARAMETERS).immutableCopy();

public void login(Map<String, String> requestParameters) {
if (!LEGAL_PARAMETERS.containsAll(requestParameters.keySet())) {
throw new IllegalArgumentException("Unrecognized parameters: "
+ Sets.difference(requestParameters.keySet(), LEGAL_PARAMETERS));
}

if (!requestParameters.keySet().containsAll(REQUIRED_PARAMETERS)) {
throw new IllegalArgumentException("Missing parameters: "
+ Sets.difference(REQUIRED_PARAMETERS, requestParameters.keySet()));
}

...
}
Unlike the traditional approach, these methods don't do any copies! Instead, they return views that delegate to the provided sets. In the occasional case when the copy is worthwhile, there's a handy method immutableCopy to give you one.