用EnumSet代替位域

如果一个枚举类型的元素主要用在集合中,一般使用int枚举模式,将2的不同倍数赋予每个常量:

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

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

test.applyStyles(STYLE_BOLD | STYLE_INALIC);

位域表示法也允许利用位操作,有效地执行像union(并集)和intersection(交集)这样的操作集合。但位域有着int枚举常量的所有缺点,甚至更多。当位域以数字形式打印时,翻译位域比翻译简单的int枚举常量要困难的多。甚至要遍历域表示的所有元素也没有很容易的方法。

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

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

// EnumSet -a modern replacement for bit fields
public class Test{
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提供了丰富的静态工厂来创建集合,其中一个如这个代码所示:

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

注意applyStyles方法采用的是Set<Style>而非EnumSet<Style>。虽然看起来好像所有的客户端都可以将EnumSet传到这个方法,但是最好的还是接受接口类型而非接受实现类型。这是考虑到可能会有特殊的客户端要传递一些其他的Set实现,并且没有什么明显的缺点。

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

ps:官方java 1.8API解释

Like most collection implementations, EnumSet is not synchronized. If multiple threads access an enum set concurrently, and at least one of the threads modifies the set, it should be synchronized externally. This is typically accomplished by synchronizing on some object that naturally encapsulates the enum set. If no such object exists, the set should be "wrapped" using the Collections.synchronizedSet(java.util.Set) method. This is best done at creation time, to prevent accidental unsynchronized access:

 Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));

用EnumSet代替位域的更多相关文章

  1. effective java——32用EnumSet代替位域

    什么是位域?为什么用到它?先来看一个例子: public class Test { public static final byte STYLE_BOLD = 1<<0; // 1 pub ...

  2. 第32条:用EnumSet代替位域

    如果一个枚举类型的元素主要用在集合中,一般使用int枚举模式,将2的不同倍数赋予每个常量: public class Text { public static final int STYLE_BOLD ...

  3. 位域(bit fields)简介

    使用位域或位操作移动一个字节中的位 Java中EnumSet代替位域代码详解 关于位域的一些东西 深入理解Java枚举类型(enum) 位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个 ...

  4. effective java 学习心得

    目的 记录一下最主要学习心得,不然凭我这种辣鸡记忆力分分钟就忘记白看了... 用静态工厂方法代替构造器的最主要好处 1.不必每次都创建新的对象 Boolean.valueOf Long.valueOf ...

  5. Effective java笔记(五),枚举和注解

    30.用enum代替int常量 枚举类型是指由一组固定的常量组成合法值的类型.在java没有引入枚举类型前,表示枚举类型的常用方法是声明一组不同的int常量,每个类型成员一个常量,这种方法称作int枚 ...

  6. 【Java基础】枚举和注解

    在Java1.5版本中,引入了两个类型:枚举类型enum type和注解类型annotation type. Num1:用enum代替int常量 枚举类型enum type是指由一组固定的常量组成合法 ...

  7. Effective Java 读书笔记之五 枚举和注解

    Java1.5中引入了两个新的应用类型家族,新的类为枚举类型,新的接口为注解类型. 一.用enum代替int常量 1.枚举值由一组固定的常量组成合法值的类型. 二.用实例域代替序数 1.不要根据枚举的 ...

  8. Effective Java 阅读笔记——枚举和注解

    30:用enum代替int常量 当需要一组固定常量的时候,应该使用enum代替int常量,除了对于手机登资源有限的设备应该酌情考虑enum的性能弱势之外. 31:用实例域代替序数 应该给enum添加i ...

  9. [Effective Java]第六章 枚举和注解

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

随机推荐

  1. 6.JS输出

    JavaScript 通常用于操作 HTML 元素. ① document.getElementById(id),可以访问某个 HTML 元素 请使用 "id" 属性来标识 HTM ...

  2. 【LeetCode】Rotate List

    Given a list, rotate the list to the right by k places, where k is non-negative. For example:Given 1 ...

  3. Boost 库编译总结

    1. 下载boost库源码,解压缩. 2. 打开vs2010 工具栏tools 下的visual studio command prompt,运行源码目录下的bootstrap.bat,生成bjam. ...

  4. (深入理解计算机系统)AT&T汇编指令

    AT&T汇编指令学习(GCC) 寄存器命名原则: 相比inter语法,AT&T语法格式要求所有的寄存器都必须加上取值符"%". 操作码命令格式: 源/目的操作数顺序 ...

  5. Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stoc

    今天在使用yum安装文件时,出现了以下问题: root@localhost opt]# yum update Loaded plugins: fastestmirror Could not retri ...

  6. 基于BASYS2的VHDL程序与烧写——按键消抖程序

    请尊重作者版权,转载请注明源地址http://www.cnblogs.com/connorzx/p/3548364.html 按键在按下的过程中通常会产生一段时间的抖动,为了消除这种抖动,一般采取两种 ...

  7. Yii的缓存机制之页面缓存

    页面缓存是不能通过片段缓存来实现的,因为布局和内容不能同时缓存.只能通过过滤器来生成缓存. 实现方法: 在控制器里使用过滤器来实现 function filters (){ return array( ...

  8. 七号信令中TUP协议的主要消息和故障问题

      CIC码说明: TUP消息的路由标记: 为OPC 24位 DPC24位 CIC 12位,12位CIC 的低5为时隙号,其中后4位为SLC,高7位为系统号.     CIC配置需要注意几个问题:   ...

  9. 51Nod - 1304 :字符串的相似度 (裸的扩展KMP)

    我们定义2个字符串的相似度等于两个串的相同前缀的长度.例如 "abc" 同 "abd" 的相似度为2,"aaa" 同 "aaab& ...

  10. 用python做自动化测试--Python实现远程性能监控

    http://blog.csdn.net/powerccna/article/details/8044222 在性能测试中,监控被测试服务器的性能指标是个重要的工作,包括CPU/Memory/IO/N ...