在Java中是否有一种位运算枚举的方法?

35

我正在使用状态机,当测试大量可能的状态时,代码变得非常冗长。

enum Mood {
    HAPPY, SAD, CALM, SLEEPY, OPTIMISTIC, PENSIVE, ENERGETIC;
}

有没有办法做到这一点:

if (currentMood == (HAPPY | OPTIMISTIC | ENERGETIC) {}

不要这样写:

if (currentMood == HAPPY || currentMood == OPTIMISTIC || currentMood == ENERGETIC) {}

在这种情况下,使用整数和标志是否更好?


8
你的意思是 if ((currentMood & (HAPPY | OPTIMISTIC | ENERGETIC)) != 0) {}。或者也许是 if (((1<<currentMood) & ((1<<HAPPY) | (1<<OPTIMISTIC) | (1<<ENERGETIC))) != 0) {}。猜测我很高兴你想要正确做好这件事。 - Tom Hawtin - tackline
我从“整数和标志”推断出,当前情绪可能不止一种。 - blizpasta
@Tom - 是的,你在技术上是正确的。我在使用类C位运算或集合理论类型语法之间徘徊不定。 - user668660
@blizpasta - 那不是我的原意,但这将是一个有用的概括。抱歉我的标题有点含糊不清。 - user668660
9个回答

49

也许可以使用类似 EnumSet 的东西?

if (EnumSet<Mood>.of(HAPPY, OPTIMISTIC, ENERGETIC).contains(currentMood))
{ 
 //Do stuff...
}

4
我认为在这种情况下你甚至可以省略<Mood>。 - Yet Another Geek
1
谢谢,这正是我在寻找的。在我看来,它比 switch-case 方法更简洁。 - user668660

18

给你的枚举类型加上 int 属性。

enum Mood {
    private int id;

    HAPPY(1), SAD(2), CALM(4), SLEEPY(8), OPTIMISTIC(16), PENSIVE(32), ENERGETIC(64);

    Mood( int id ) {
        this.id = id;
    }
}

在if语句中,对这个属性进行测试。

if ( currentMood & ( HAPPY.id | OPTIMISTIC.id | ENERGETIC.id ) != 0 ) { ... }

1
如果您对源代码的排序有信心(一个相当大的“如果”),您也可以直接使用ordinal() - Darien
5
你不能使用ordinal()方法,因为它会给你0123等,这些不适用于按位或运算。 - isapir
6
有些迟了,但你可以尝试 1 << ordinal() - Yet Another Geek
没有公共的getter方法,id应该是final public的。 - Blessed Geek
只要枚举类型最多有32个常量(通常情况下),您可以使用ordinal()来创建唯一的“掩码”值,例如1 << ordinal()。如果常量数量高达64,则可以使用long类型的掩码。这就是EnumSet在小型枚举中的实现方式。 - Valentin Ruano

5

除了其他答案之外:如果该特定状态集在您的应用程序中具有语义上定义的含义(与您的特定方法相对独立,特定于Enum),我建议将该测试作为同一Enum类中的方法包含。

enum Mood {
     HAPPY, SAD...

     public boolean isRatherPositive() {
       ....
     }

}

任何一个逻辑建议中提到的(我更喜欢EnumSet,它可以静态或惰性实例化)都可以实现静态方法。

将方法放在枚举中有助于避免代码重复,但最重要的是,可以防止在添加成员或修改枚举时出现错误。


2

是的

switch(currentmood){
    case HAPPY:
    case OPTIMISTIC:...
        Then do this
        break;
    default://else
}

这是一个不错的方法,但可以提供更多的背景信息,以更好地与问题相关联。 - undefined

1
你可以给你的枚举类型添加一个布尔标志,并测试它。
enum Mood {
    HAPPY(true), SAD, CALM, SLEEPY, OPTIMISTIC(true), PENSIVE, ENERGETIC(true);
    final boolean good;

    Mood(){this(false);}

    Mood(boolean isgood){this.good = isgood;}

    public isGood(){return good;}
}

这样检查很简短

if (currentMood.isGood()) {}

1

一种方法是使用EnumSet/switch/if等。如果您正在以某种方式对枚举进行分类,而这种方式并不是枚举本身固有的部分,则这是有意义的。例如,颜色是否是国旗颜色的一部分。'依赖模型'是国旗依赖于颜色,但颜色并不关心国旗的存在。

另一方面,如果您试图确定颜色是否为原色(人类颜色模型的内在属性),则它属于枚举类本身。所以,

enum Color {
  private final boolean _crtPrimary;

  Red(true), Green(true), Blue(true), Black(false)

  Color(boolean crtPrimary) {
    _crtPrimary = crtPrimary;
  }

  public boolean isCRTPrimary() {
    return _crtPrimary;
  }
}

0

当您使用 || 运算符时,每次必须指定要比较的两个值。不过,您可以轻松编写一个小方法来完成这个任务。

if (currentMood.hasMood(HAPPY, OPTIMISTIC, ENERGETIC)) {}

public boolean hasMood(Mood ....)

0

你可以使用 YourEnum.values()

例如,我有一个名为 Enumerations 的类。在这个类中,我有多个枚举类。

例如:

public class Enumerations {

public enum smtg
{
    Fast(1),
    Slow(2);

    private int number;
    private smtg(final int num) { number = num; }
    public int getsmtg()
    {
        return number;
    }
}
......

}

当我想使用位运算时,我只需像这样使用它:

Enumerations.smtg.values()[Enumerations.smtg.Slow.ordinal() | Enumerations.smtg.Fast.ordinal()]

-1

另一个选项:

public enum PaymentResponse {
    PP_SUCCESS, PP_FAILURE, CC_SUCCESS, CC_FAILURE;

    public boolean isSuccessful() {
            return ordinal() == CC_SUCCESS.ordinal()  ||  
                   ordinal() == PP_SUCCESS.ordinal() ;
    }
}

为什么不直接写成 return this == CC_SUCCESS || this == PP_SUCCESS; 呢? - Wulf
同意Wulf的观点 - Geir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接