美文网首页
第三十六条:用EnumSet代替位域

第三十六条:用EnumSet代替位域

作者: taogan | 来源:发表于2021-02-20 11:47 被阅读0次

如果一个枚举的元素主要用在集合中,一般就使用int枚举模式(详见第34条),比如将2的不同倍数赋予每个常量:

// Bit field enumeration constants - OBSOLETE!
public class Text {
  public static final int STYLE_BOLD = 1 << 0; // 1
  public static final int STYLE_ITALIC = 1 << 1; // 2
  public static final int STYLE_UNDERLINE = 1 << 2; // 4 
  public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8
  // Parameter is bitwise OR of zero or more STYLE_ constants
  public void applyStyles(int styles) { ... } 
}

这种表示法让你用OR位运算将几个常量合并到一个集合中,称作位域(bit field):

text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

位域表示法也允许利用位操作,有效的执行像union(联合)和intersection(交集)这样的集合操作。但位域具有int枚举常量的所有缺点,甚至更多。当位域以数字形式打印时,翻译位域比翻译简单的int枚举常量要困难得多。要遍历位域表示的所有元素也没有很容易的方法。最后一点,在编写API的时候,就必须先预测最多需要多少位,同时还要给位域选择对应的类型(一般是int或者long)。一旦选择好类型。在没有修改API的情况下,将不能超出其位宽度(如32位或者64位)。

有些程序员虽然更倾向于使用枚举而非int常量,但是他们在需要传递多组常量集时,仍然倾向于使用位域。其实没有理由这么做,因为还有更好的替代方法。java.util包提供了EnumSet类来有效的表示从单个枚举类型中提取的多个值的多个集合。这个类实现Set接口,提供了丰富的功能、类型安全性,以及可以从任何其他Set实现得到的互用性。但是在内部具体的实现上,每个EnumSet内容都表示为矢量。如果底层的枚举类型有64个或者更少的元素(大多如此)整个EnumSet就是用单个long来表示,因此它的性能比得上位域的性能。批处理操作,比如remvoeAll和retainAll,都是利用位算法来实现的,就像手工替位域实现的那样。但是可以避免手工位操作时容易出现的错误以及丑陋的代码,因为EnumSet替你完成了这项艰巨的工作。

下面是前一个范例改成用枚举代替位域之后的代码,它更加简洁、更加清楚,也更加安全:

// EnumSet - a modern replacement for bit fields
public class Text {
  public enum Style { BOLD, ITALIC, UNDERLINE,STRIKETHROUGH }
  // Any Set could be passed in, but EnumSet is clearly best
  public void applyStyles(Set<Style> styles) { ... } 
}

下面是将EnumSet实例传递给applyStyles方法的客户端代码。EnumSet提供了丰富的静态工厂来轻松创建集合,其中一个如下代码所示:

text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));

注意applyStyles方法采用的是Set<Style>而非EnumSet<Style>。虽然看起来好像所有的客户端都可以将EnumSet传到这个方法,但是最好还是接收接口类型而非接收实现类型(详见第64条)。这是考虑到可能会有特殊的客户端需要传递一些其他的Set实现。

总而言之,正是因为枚举类型要用在集合中,所以没有理由用位域来表示它。EnumSet类集位域的简洁和性能优势及第34条中所述的枚举类型的所有优点于一身。实际上EnumSet有个缺点,即截至Java9发行版本,它都无法创建不可变的EnumSet,但是这一点很可能在即将发布的版本中得到修正。同时,可以使用Collections.unmodifiableSet将EnumS封装起来,但是间接性和性能会受到影响。

相关文章

网友评论

      本文标题:第三十六条:用EnumSet代替位域

      本文链接:https://www.haomeiwen.com/subject/gxrtfltx.html