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?

Was it helpful?

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 =).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top