10

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?

informatik01
  • 16,038
  • 10
  • 74
  • 104
Roalt
  • 8,330
  • 7
  • 41
  • 53

5 Answers5

7

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);
Aravindan R
  • 3,084
  • 1
  • 28
  • 44
2

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.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • Yeah I have used BitSet for flags in the final exam of one of my classes last semester. It was an elegant solution that no other student used and my prof really liked it. :) I would encourage people to use BitSet more, it doesn't seem to be used a lot. – RestInPeace Nov 12 '14 at 01:22
2

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.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
1

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));
bertvanbrakel
  • 69
  • 1
  • 1
0

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

John Hart
  • 5,718
  • 2
  • 20
  • 12