1

So I'm converting some bitfields in our application to use EnumSet instead, and I'm curious if there's a better way to do a comparison for X|Y. Currently we do something like:

if(bitfield & (X | Y) != 0) {
    //do stuff
}

The EnumSet equivalent seems to be:

if(enumSet.contains(X) || enumSet.contains(Y)) {
    //do stuff
}

Is there a cleaner way to do this? I know you can check for containsAll() like so:

EnumSet flagsToCheck = EnumSet.of(X, Y);
if(enumSet.containsAll(flagsToCheck)) {
    //do stuff
}

But that's for a scenario where you want to know if (X & Y) is set. Is there an equivalent way to check for (X | Y)? I would think there would be something like a containsAny() method, but I don't see anything that seems to have that effect.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274

3 Answers3

7

I would say the existing approach is more readable than your bitwise approach. It says exactly what you mean: if the set contains X, or the set contains Y... Keep it as it is. It's already clean.

If the set becomes larger, you could use:

EnumSet<Foo> valid = EnumSet.of(Foo.X, Foo.Y, Foo.A, Foo.B);
valid.retainAll(enumSet);
if (valid.isEmpty()) {
    ...
}

But I'd only keep that for larger cases. For two or three options I'd use the longhand form.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    You possibly want the opposite (`!valid.retainAll(enumSet)`) to avoid changing the original set. – assylias Feb 25 '13 at 19:56
  • I was about to comment as to @assylias's point. You're probably right that it's more readable as individuals for small sets, just seems sort of verbose. – Kevin Coppock Feb 25 '13 at 19:57
  • 2
    @kcoppock: I prefer "verbose" over "clever" any day, when it's actually quicker to read. With bitmasking operations I'd probably have to double-check it every time - whereas with the simple "X or Y" the code reads really naturally. – Jon Skeet Feb 25 '13 at 20:09
  • @assylias is right. An option to that is to just create a new set based on the enum values you want and change/verify accordingly. – Marcello DeSales Nov 15 '13 at 21:24
1

You can use the AbstractSet method removeAll (true if any of the elements was found). Obviously, probably you want to do that with a clone of the original set.

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • True, that's a good way to check as well. I just wanted to avoid an unnecessary copy. – Kevin Coppock Feb 25 '13 at 19:55
  • 1
    assylias comment of doing the opposite (removeAll of the original set from the set of values you are looking for) also applies here. – SJuan76 Feb 25 '13 at 22:31
1

If you can't update the set, just create a new one... @assylias is right. An option to that is to just create a new set based on the enum values you want and change/verify accordingly.

public enum ResultingState {
    NOT_PERSISTED, PERSISTED, NOT_CALCULATED, CALCULATED;
}
EnumSet<ResultingState> errorsState = EnumSet.of(ResultingState.NOT_PERSISTED, ResultingState.NOT_CALCULATED);
Collection<ResultingState> results = new HashSet<>(phaseResults.values());
boolean containsAny = results.retainAll(errorsState) && results.size() > 0;
Marcello DeSales
  • 21,361
  • 14
  • 77
  • 80