用EnumSet代替位域
用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代替位域的更多相关文章
- effective java——32用EnumSet代替位域
什么是位域?为什么用到它?先来看一个例子: public class Test { public static final byte STYLE_BOLD = 1<<0; // 1 pub ...
- 第32条:用EnumSet代替位域
如果一个枚举类型的元素主要用在集合中,一般使用int枚举模式,将2的不同倍数赋予每个常量: public class Text { public static final int STYLE_BOLD ...
- 位域(bit fields)简介
使用位域或位操作移动一个字节中的位 Java中EnumSet代替位域代码详解 关于位域的一些东西 深入理解Java枚举类型(enum) 位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个 ...
- effective java 学习心得
目的 记录一下最主要学习心得,不然凭我这种辣鸡记忆力分分钟就忘记白看了... 用静态工厂方法代替构造器的最主要好处 1.不必每次都创建新的对象 Boolean.valueOf Long.valueOf ...
- Effective java笔记(五),枚举和注解
30.用enum代替int常量 枚举类型是指由一组固定的常量组成合法值的类型.在java没有引入枚举类型前,表示枚举类型的常用方法是声明一组不同的int常量,每个类型成员一个常量,这种方法称作int枚 ...
- 【Java基础】枚举和注解
在Java1.5版本中,引入了两个类型:枚举类型enum type和注解类型annotation type. Num1:用enum代替int常量 枚举类型enum type是指由一组固定的常量组成合法 ...
- Effective Java 读书笔记之五 枚举和注解
Java1.5中引入了两个新的应用类型家族,新的类为枚举类型,新的接口为注解类型. 一.用enum代替int常量 1.枚举值由一组固定的常量组成合法值的类型. 二.用实例域代替序数 1.不要根据枚举的 ...
- Effective Java 阅读笔记——枚举和注解
30:用enum代替int常量 当需要一组固定常量的时候,应该使用enum代替int常量,除了对于手机登资源有限的设备应该酌情考虑enum的性能弱势之外. 31:用实例域代替序数 应该给enum添加i ...
- [Effective Java]第六章 枚举和注解
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
随机推荐
- Ubuntu上Eclipse安装PyDev方法和配置
Ubuntu11.10中Eclipse安装PyDev插件方法 PyDev是Eclipse中用来开发python的一个插件,个人比较喜欢,下面介绍在Ubuntu下安装这个插件的方法.(在Windows下 ...
- 九度OJ 1098:字母统计 (计数)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3720 解决:1809 题目描述: 输入一行字符串,计算其中A-Z大写字母出现的次数 输入: 案例可能有多组,每个案例输入为一行字符串. 输 ...
- java socket相关的timeout
1 java socket的两个timeout 一个是connect timeout,即建立连接的timeout,另外一个是so timeout,是读取数据的timeout.这两个timeout都是因 ...
- STM32 ~ 查看系统时钟
调用库函数RCC_GetClocksFreq,该函数可以返回片上的各种时钟的频率 函数原形 void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks) ...
- emWin 移植 - 基于红牛开发板
一直想利用所学的东西自己设计一个精致一些的作品,手头正好有一块红牛开发板,就先用它来写一些软件,熟悉一下过程和一些想法的可行性.首先当然是选择一个操作系统了,对比了几种之后选择了emWin.那就移植一 ...
- 操作系统:使用AT&T实现引导扇区
参考学习于渊的书箱时,里面都是用nasm来写的,而自己更熟悉和使用AT&T的语法,心想用AT&T来实现一下,这个过程是十分漫长与痛苦的,但也收获颇丰. 1. 引导扇区代码 .code1 ...
- ImageIO 操作图片
/** * 读取本地图片到另一个本地文件夹 * @throws IOException */ public void copeImageToOtherFolder() throws IOExcepti ...
- 创建一个catkin工作空间
先确定自己的环境变量是否设置正确 export | grep ROS 若出现如下的,说明是正确的 declare -x ROSLISP_PACKAGE_DIRECTORIES="" ...
- HDU5015 233 Matrix —— 矩阵快速幂
题目链接:https://vjudge.net/problem/HDU-5015 233 Matrix Time Limit: 10000/5000 MS (Java/Others) Memor ...
- IPFS 到底是怎么工作的?
简介 我们知道,一个存储服务,最基本的功能就是存和取.IPFS 中提供了这两种语义,那就是 add 和 get 操作. 在 IPFS 系统中执行 add 操作,就是执行了一次存操作,放在网络的概念里, ...