Effective Java读书笔记十(Java Tips.Day.10)
来源:互联网 发布:c语言入门到精通光盘 编辑:程序博客网 时间:2024/06/08 14:42
TIP32 用EnumSet替代位域
看看下一段代码:
public class Text{ public static final int STYLE_BOLD = 1<<0; public static final int STYLE_ITALY = 1<<1; public static final int STYLE_UNDERLINE = 1<<2; public static final int STYLE_STRIKETHOUGH = 1<<3; public void applyStyles(int style){ //.... } }
然后你可以用OR这个运算符将几个常量合并到一个集合中,称作位域(bit field)。
text.applyStyles(STYLE_BOLD | STYLE_ITALY);
然而位域也有其缺点:如果打印一个位域,翻译位域比翻译简单的int枚举常量要苦难的多,要遍历位域表示的所有元素也不太容易。 而且,它貌似也阻止了程序员将这组常量转变为枚举实现,而它的优点,我仅仅能想到它的执行效率会很高。
下面考虑用EnumSet来实现:
public class Text{ public enum Style{ BOLD,ITALIC,UNDERLINE,STRIKETHROUGH; } public void applyStyles(Set<Style> styles){ //... } }
然后,这样来使用它:
text.applyStyles(EnumSet.of(Style.BOLD,Style.ITALIC,Style.UNDERLINE));
总之,正式因为枚举类型要用在集合中,所以没有必要用位域来表示它。
EnumSet显然拥有位域的简洁和性能优势,同时有枚举类型所有的有点。
当然,它也有缺点,在JAVA 1.6版本时,它都无法创建不可变的EnumSet。或许可以考虑用Collections.unmodifiableSet将EnumSet封装起来,但简洁性和性能会收到影响。
TIP33 用EnumMap替代序数索引
参考31条,你可能会见到利用ordinary方法来索引数组的代码。例如下面这个过于简化的类,用来表示一种烹饪用的香草:
public static class Herb{ public enum Type{ ANNUAL,PERSENAL,BIENNIAL } private final String name; private final Type type; public Herb(String name, Type type) { this.name = name; this.type = type; } @Override public String toString() { return name; } }
现在假设有一个香草的数组,表示一座花园中的植物,你想按照类型(一年生,二年生,多年生)进行组织之后将这些植物列出来:
Herb[] garden = ...; //这里必须有个未受检的警告...具体参考泛型的相关TIPS Set<Herb>[] herbsByType = (Set<Herb>[]) new Set[Type.values().length](); for (int i=0;i < herbsByType.length;i++){ herbsByType[i] = new HashSet<>(); } for (Herb h:garden) { herbsByType[h.type.ordinal()].add(h); } for (int i=0;i<herbsByType.length;i++){ System.out.printf("%s:%S%n",Herb.Type.values()[i],herbsByType[i]); }
这段代码希望herbsByType的索引正好对应Herb.Type的ordinary(),而这些工作,都需要程序员本身来维护,使它们正常工作。一旦发生错误,程序就会完成错误的工作,抛出数组越界异常都算是幸运的事情了。
要维护这种对应关系,使用Map是更好的选择。而EnumMap则是一种专门用于枚举键的Map实现。下面是修改后的实现:
Herb[] garden = ....; Map<Herb.Type,Set<Herb>> herbsByType = new EnumMap<Type, Set<Herb>>(Herb.Type.class); for (Herb.Type t:Herb.Type.values()) { herbsByType.put(t,new HashSet<Herb>()); } for (Herb h:garden){ herbsByType.get(h.type).add(h); } System.out.println(herbsByType);
这段程序更简短,清楚,也更安全,性能可以与使用序数的程序媲美。映射关系则被隐藏和封装起来了,无需程序员另外维护。
注意EnumMap的构造方法采用键类型的Class对象:这是一个有限制的类型令牌(bounded type token),它提供了运行时的泛型信息。
总之,最好不要用序数来索引数组,而要使用EnumMap。如果需要维护的关系是多维的,就使用
EnumMap
- Effective Java读书笔记十(Java Tips.Day.10)
- Effective Java读书笔记二十(Java Tips.Day.20)
- Effective Java读书笔记一(Java Tips.Day.1)
- Effective Java读书笔记二(Java Tips.Day.2)
- Effective Java读书笔记五(Java Tips.Day.5)
- Effective Java读书笔记六(Java Tips.Day.6)
- Effective Java读书笔记八(Java Tips.Day.8)
- Effective Java读书笔记九(Java Tips.Day.9)
- Effective Java读书笔记十一(Java Tips.Day.11)
- Effective Java读书笔记十二(Java Tips.Day.12)
- Effective Java读书笔记十三(Java Tips.Day.13)
- Effective Java读书笔记十四(Java Tips.Day.14)
- Effective Java读书笔记十五(Java Tips.Day.15)
- Effective Java读书笔记十六(Java Tips.Day.16)
- Effective Java读书笔记十七(Java Tips.Day.17)
- Effective Java读书笔记十九(Java Tips.Day.19)
- Effective Java读书笔记二一(Java Tips.Day.21)
- Effective Java读书笔记二二(Java Tips.Day.22)
- 一个简单的servlet2,response的使用,文件下载
- Mac OS下 Anaconda Python2 和 Python3 配置
- 由数据分布看出IN和EXISTS区别
- 刘汝佳《算法竞赛入门经典(第二版)》习题(五)
- MapReduce编程实例:二次排序
- Effective Java读书笔记十(Java Tips.Day.10)
- 下拉刷新控件
- 如何解决Ubuntu14.04安装32位兼容库的问题
- SDNU 1031.字母排序 拓扑排序
- jquery监听动态加载的对象的click方法
- 机器学习实战-第一章(机器学习基础)
- Coredump调试方法
- 用Collections.sort方法对list排序有两种方法
- 随想