Java: would you use an EnumSet in this case

enumjava

I have this weird scenario in which some Java property is used to build and HQL query, and the type of the field is Boolean, i.e. it is boxed. I wondered why because I don't really like to think of booleans as having three possible values, true, false, and null. I recently found out the null value actually has semantics in this system. The semantics are: true means "only unviewed", false means "only viewed", and null means "all". So, if null, the field is ignored when building the HQL query, so that the end result contains both unviewed and viewed results.

In my opinion this is a case where an enum should be used. Something like this:

enum ViewStatus {
  VIEWED, UNVIEWED;
}

My dilemma now is what to use for the third case that should represent the union of these two constants? The two options are:

  1. Introduce a third enum constant, ALL.

    enum ViewStatus {
      VIEWED, UNVIEWED, ALL;
    }
    
  2. Use an EnumSet.

EnumSet pretty much exists specifically for this purpose, but… it seems like just two much overhead. Especially when reading the values in the part of the code that builds the HQL.

So, what are your thoughts? Shall I go with a third enum constant and refactor to EnumSet when need arises?

Thanks!

Update

I'll go for an EnumSet because I want to introduce methods on that enum that wouldn't make sense to be called on ALL. For example ViewStatus.isViewed().

Best Answer

I rather avoid things like

ViewStatus viewStatus;

since it introduces a new class without giving you anything in return when compared to

boolean isViewed;

But that's a matter of personal taste.


By setting the reference to null you can have a third value, which is not really good, since you can get an unexpected NPEsomewhere; null is just no "first class value".

EnumSet pretty much exists specifically for this purpose, but... it seems like just two much overhead. Especially when reading the values in the part of the code that builds the HQL.

The overhead of an EnumSet is reasonable, it caches the class and an array of all values, and uses a long for storing the data (as long as the enum is small enought). Its equals method is quite fast, but obviously slower than reference comparison. You mentioned using HQL, so most probably the runtime will be dominated by the database access, so IMHO you're needless and premature optimization.

The mutability of the EnumSet may be a problem sometimes, but there's ImmutableEnumSet in guava.


I'll go for an EnumSet because I want to introduce methods on that enum that wouldn't make sense to be called on ALL. For example ViewStatus.isViewed().

I don't think you stated all your alternatives right. You can have both

enum ViewStatus {VIEWED, UNVIEWED}

and

enum ViewStatuses {VIEWED, UNVIEWED, ALL}

where the second is an replacement for the EnumSet. That said, I agree with your decision.