Effective Java(3rd)-Item36 使用EnumSet代替位字段

  如果枚举类型的元素主要用于集合,传统上使用int枚举类型( item34)为每个常量分配2的不同幂:

Effective Java(3rd)-Item36 使用EnumSet代替位字段_第1张图片
image.png

  该表示形式允许你使用按位或操作将数个常量组成一个集合,称为位字段:
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);
  位字段表示还允许你使用按位算法高效的执行集合操作,如并和交。但是位字段有int常量和更多的缺点。当一个位字段被打印为一个数字时,它比一个简单的int枚举常量更加难解释。没有一种简单的方法来迭代由位字段表示的所有元素。最后,你必须预测在编写API时所需的最大位数,并相应地为位字段选择一个类型(通常位int或long)。一旦你选择了一个类型,如果不更改API,就不能超过它的宽度(32或64位)。
  一些优先使用枚举而不是int常量的程序员在需要传递一组常量时仍然坚持使用位字段。没有理由这么做,因为有更好的替代方法存在。java.util包提供了EnumSet类来高效的表示从单个枚举类型中提取的值集。这个类实现了Set接口,提供所有的丰富,类型安全和从其他Set实现中的互操作性。但是在内部,每个EnumSet都表示为位向量。如果基础枚举类型有64个或更少的原色(大多数是这样的),则整个EnumSet由一个single long表示,因此它的性能可与位字段的性能相媲美。扩展操作,比如removeAll,和retainAll,使用按位算数实现,就像手动处理位字段一样。但是你不受手工旋转的丑陋和错误倾向的影响:EnumSet为你做了艰苦的工作。
  下面是前面的实例在修改以使用枚举和枚举set而不商位字段的样子。它更短,更清晰,更安全:


Effective Java(3rd)-Item36 使用EnumSet代替位字段_第2张图片
image.png

  下面是将EnumSet实例传递到applyStyles方法的客户端代码。EnumSet类为易于创建集提供了一组丰富的静态工厂,其中之一在下面的代码中得到了说明:
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
  注意applyStyles方法使用Set