Edited at

複数のフラグからマッチするEnumオブジェクトを取得する(ビット演算とEnumSet)

More than 3 years have passed since last update.


やりたいこと

こんなかんじのフラグのセットを受け取って

boolean useSaba = true;

boolean useTori = false;
boolean useNira = false;
boolean isOomori = true;

マッチするEnumオブジェクトを取得したい。

(上のフラグの場合は LunchSet.SABA_DAI

enum LunchSet {

GOHAN("ご飯セット"),
SABA("サバ味噌定食"),
TORI("トリ唐揚定食"),
NIRA("ニラ炒め定食"),
GOHAN_DAI("ご飯セット大盛り"),
SABA_DAI("サバ味噌定食大盛り"),
TORI_DAI("トリ唐揚定食大盛り"),
NIRA_DAI("ニラ炒め定食大盛り");

private final String name;
private LunchSet(String name) {
this.name = name;
}
public String getName() {
return name;
}
}


方法1 ビット演算


  • Enumのコンストラクタにビット演算用の数値を追加する。

  • 数値を元にマッチするEnumオブジェクトを返すメソッドを定義する。

enum LunchSet {

GOHAN("ご飯セット", 0),
SABA("サバ味噌定食", 1),
TORI("トリ唐揚定食", 2),
NIRA("ニラ炒め定食", 4),
GOHAN_DAI("ご飯セット大盛り", 8),
SABA_DAI("サバ味噌定食大盛り", 9),
TORI_DAI("トリ唐揚定食大盛り", 10),
NIRA_DAI("ニラ炒め定食大盛り", 12);

private final String name;
private final int flag;
private LunchSet(String name, int flag) {
this.name = name;
this.flag = flag;
}
public String getName() {
return name;
}
public int getFlag() {
return flag;
}
public static LunchSet getByFlag(int flag) {
return Arrays.stream(values())
.filter(s -> s.getFlag() == flag)
.findFirst()
.orElse(LunchSet.GOHAN);
}
}

こんなふうにフラグからビットの論理和を求めて取得できる。

        int flag = 0;

if (useSaba) { flag += 1; }
if (useTori) { flag += 2; }
if (useNira) { flag += 4; }
if (isOomori) { flag += 8; }
LunchSet lunchSet = LunchSet.getByFlag(flag);

でもビット演算はちょっとわかりづらい。


方法2 EnumSet

Effective Javaで有名なビット演算の置き換え。

enum Menu {

SABA,
TORI,
NIRA,
OOMORI;
}

enum LunchSet {
GOHAN("ご飯セット", EnumSet.noneOf(Menu.class)),
SABA("サバ味噌定食", EnumSet.of(Menu.SABA)),
TORI("トリ唐揚定食", EnumSet.of(Menu.TORI)),
NIRA("ニラ炒め定食", EnumSet.of(Menu.NIRA)),
GOHAN_DAI("ご飯セット大盛り", EnumSet.of(Menu.OOMORI)),
SABA_DAI("サバ味噌定食大盛り", EnumSet.of(Menu.SABA, Menu.OOMORI)),
TORI_DAI("トリ唐揚定食大盛り", EnumSet.of(Menu.TORI, Menu.OOMORI)),
NIRA_DAI("ニラ炒め定食大盛り", EnumSet.of(Menu.NIRA, Menu.OOMORI));

private final String name;
private final EnumSet<Menu> flag;
private LunchSet(String name, EnumSet<Menu> flag) {
this.name = name;
this.flag = flag;
}
public String getName() {
return name;
}
public EnumSet<Menu> getFlag() {
return flag;
}
public static LunchSet getByFlag(EnumSet<Menu> flag) {
return Arrays.stream(values())
.filter(s -> s.getFlag().equals(flag))
.findFirst()
.orElse(LunchSet.GOHAN);
}
}

こんなふうにEnumSetのフラグから取得できる。

        EnumSet<Menu> flag = EnumSet.noneOf(Menu.class);

if (useSaba) { flag.add(Menu.SABA); }
if (useTori) { flag.add(Menu.TORI); }
if (useNira) { flag.add(Menu.NIRA); }
if (isOomori) { flag.add(Menu.OOMORI); }
LunchSet lunchSet = LunchSet.getByFlag(flag);

コード量が増えるのが難点だけど、ビット演算よりは何をしているのかわかるようになり、Enumからフラグのセットを求める逆の操作もやりやすい。