Best practice of using flags in Java method
Question
What's the best practice for specifying flags in a Java method?
I've seen SWT using int as bitfields, like:
(example partially from "Effective Java, 2nd Ed." page 159):
public class Text {
public static final int STYLE_BOLD = 1 << 0; // 1
public static final int STYLE_ITALIC = 1 << 1; // 2
void printText(String text, int flags) {
}
}
and your client call looks like:
printText("hello", Text.STYLE_BOLD | Text.STYLE_ITALIC);
..but this is discouraged as you can mixed flags (int values) from different classes together without any compiler checks.
In the same book ("Effective Java"), I see the use of EnumSet, but then your user call becomes:
printText("hello", EnumSet.of(Style.Bold, Style.ITALIC));
I find this a bit verbose and I prefer the elegance of SWT.
Is there any other alternative or is this basically the two tastes you must pick?
Solution
Guess you have hit a wall. I don't see any other option. Java is verbose that's a fact. In situations like this i usually add a local variable to make the code more readable. You can do this,
EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.ITALIC);
printText("hello", styles);
OTHER TIPS
If you want bit style flags, Java wraps them in a BitSet
. It's been around for ages, yet few people bother to use it (preferring embedding C style bit handling in ints).
The api for BitSet can be found here.
Coupled with a few well chosen static ints, it does pretty well until you start getting into checking and setting multiple bits in one pass.
I advise that you go with the EnumSet
approach.
EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.Italic);
This approach provides better type safety, and Style
being an enum will have full-blown OO capabilities.
Late answer for anyone coming across this. Here is one way to do it to reduce memory and have a nice enum like api:
public static class MyFlag {
public static final MyFlag A = new MyFlag(1<<0);
public static final MyFlag B = new MyFlag(1<<1);
public static final MyFlag C = new MyFlag(1<<2);
public static final MyFlag ALL = A.and(B).and(C);
private final int flag;
private MyFlag(int flag){
this.flag = flag;
}
public MyFlag and(MyFlag limit){
return new MyFlag(flag & limit.flag);
}
public MyFlag not(MyFlag limit){
return new MyFlag(flag | ~limit.flag);
}
public boolean isSet(MyFlag limit){
if(limit ==null){
return false;
}
return (this.flag & limit.flag) != 0;
}
}
method:
public void doFoo(MyFlag flag){
if(MyFlag.A.isSet(flag)){
....
}
if(MyFlag.C.isSet(flag)){
....
}
}
call:
x.doFoo(MyFlag.A.and(MyFlag.C));
If you only have a limited number of methods that will be taking a set of styles (like printText
, in your example), you can tweak their signature to take a variable number of Style params:
void printText(String text, Style... flags) {
EnumSet<Style> style = logicalOr(flags); // see comment below
...
}
And then your calls are very close to the untyped (int) flag route:
printText("hello", Style.BOLD, Style.ITALIC);
Sadly, there is no EnumSet.of(E... )
factory, just EnumSet.of(E first, E... more)
, so you'll need a generic logicalOr
method to split your array into first + rest chunks. Left as an exercise to the reader =).