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:
Introduce a third enum constant,
ALL
.enum ViewStatus { VIEWED, UNVIEWED, ALL; }
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()
.
2 Answers 2
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 NPE
somewhere; 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.
-
Hm, actually, I think your last suggestion makes quite a lot of sense. I'll sleep a bit on the idea of dropping the
EnumSet
and introduce a second enum. The logic would be that the first enum applies to individual entities, while the second applies to collection of entities.Ionuț G. Stan– Ionuț G. Stan2011年09月01日 08:16:15 +00:00Commented Sep 1, 2011 at 8:16
In this situation I use this pattern :
public class ViewStatusTest {
public final static class ViewStatus {
public static final ViewStatus FALSE = new ViewStatus();
public static final ViewStatus TRUE = new ViewStatus();
public static final ViewStatus ALL = new ViewStatus();
private ViewStatus() {
}
}
/** @param args */
public static void main(final String[] args) {
final ViewStatus vs = ViewStatus.TRUE;
if(ViewStatus.FALSE == vs) {
System.out.println("FALSE");
} else if(ViewStatus.TRUE == vs) {
System.out.println("TRUE");
} else {
System.out.println("ALL");
}
}
}
It is optimised because it test on internal address (not to necessary to load object and look inside).
In hope it will be usefull for HQL.
Best regards
-
4You're just implementing an
enum
manually as everybody had to before Java 5. It works fine but offers no single advantage when compared to anenum
(you really should also implementtoString
and maybe other methods likecompareTo
orordinal
).maaartinus– maaartinus2011年09月01日 07:31:12 +00:00Commented Sep 1, 2011 at 7:31
EnumSet
, even if the comprehension radius is a bit greater, just because I had to put methods on that enum that would trigger WTFs if called on theALL
constant.