有时候,会见到利用ordinal方法来索引数组的代码。例如下面这个简化的类,表示一种烹饪用的香草:

public class Herb {
public enum Type { ANNUAL, PERENNIAL, BIENNIAL } private final String name;
private final Type type; Herb(String name, Type type) {
this.name = name;
this.type = type;
} @Override
public String toString() {
return name;
} }

假设有一个香草的数组,表示一座花园中的植物,想要按照类型(一年生、多年生或者两年生植物)进行组织后将植物列出来。

1.将集合放到一个按照类型的序数进行索引的数组中实现:

public static void main(String[] args) {
Herb[] garden = {new Herb("a", Herb.Type.ANNUAL), new Herb("b", Herb.Type.BIENNIAL)}; Set<Herb>[] herbsByType = (Set<Herb>[]) new Set[Herb.Type.values().length];
for(int i=0; i < herbsByType.length; i++)
herbsByType[i] = new HashSet<Herb>();
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]);
}

这种方法可行,但是由于数组与泛型不兼容,需要进行未受检的转换。

2.更好的方法,数组实际上充当从枚举到值的映射,EnumMap提供这样的实现:

public static void main(String[] args) {
Herb[] garden = {new Herb("a", Herb.Type.ANNUAL), new Herb("b", Herb.Type.BIENNIAL)};
Map<Herb.Type, Set<Herb>> herbByType = new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);
for(Herb.Type t : Herb.Type.values())
herbByType.put(t, new HashSet<Herb>());
for(Herb h : garden)
herbByType.get(h.type).add(h);
System.out.println(herbByType);
}

不存在不安全的类型转换。

还可能遇到按照序数进行两次索引的数组的数组

public enum Phase {
SOLID, LIQUID, GAS;
public enum Transition {
MELT, FREEZE, BOTL, CONDENSE, SUBLIME, DEPOSIT;
private static final Transition[][] TRANSITIONS = {
{null, MELT, SUBLIME},
{FREEZE, null, BOTL},
{DEPOSIT, CONDENSE, null}
};
public static Transition from(Phase src, Phase dst) {
return TRANSITIONS[src.ordinal()][dst.ordinal()];
}
}
}

利用EnumMap可以做的更好:

public enum Phase {
SOLID, LIQUID, GAS; public enum Transition {
MELT(SOLID,LIQUID), FREEZE(LIQUID, SOLID),
BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),
SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID); private final Phase src;
private final Phase dst; Transition(Phase src, Phase dst) {
this.src = src;
this.dst = dst;
} private static final Map<Phase, Map<Phase, Transition>> m =
new EnumMap<Phase, Map<Phase, Transition>>(Phase.class);
static {
for(Phase p : Phase.values())
m.put(p, new EnumMap<Phase, Transition>(Phase.class));
for(Transition t : Transition.values())
m.get(t.src).put(t.dst, t);
} public static Transition from(Phase src, Phase dst) {
return m.get(src).get(dst);
}
}
}

不需要平方级大小的数组。

如果增加一个新的阶段plasma(离子),只有两个过渡与这个阶段关联,电离化,将气体变成离子,消电离化,将离子变成气体。

基于数组的程序,必须给Phase添加一个PLASMA常量,给Phase.Transition添加两种常量,用新的16个元素的版本取代原来9个元素的数组的数组,这很容易出错。

基于EnumMap的版本,所要做的只是将PLASMA添加到Phase列表,并把IONIZE(GAS, PLASMA), DEIONIZE(PLASMA, GAS) 添加到Phase.Transition列表中,出错的概率很小。

第33条:用EnumMap代替序数索引的更多相关文章

  1. Effective Java 第三版——37. 使用EnumMap替代序数索引

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  2. 用EnumMap代替序数索引

    用EnumMap代替序数索引   有时候,会见到利用ordinal方法来索引数组的代码.例如下面这个简化的类,表示一种烹饪用的香草: public class Herb { public enum T ...

  3. 【Effective Java】9、使用EnumMap代替序数索引

    package cn.xf.cp.ch02.item33; import java.util.EnumMap; import java.util.HashSet; import java.util.M ...

  4. 使用 ENUMMAP 替代序数索引

    import java.util.Arrays; import java.util.EnumMap; import java.util.HashSet; import java.util.Map; i ...

  5. 33条C#、.Net经典面试题目及答案

    33条C#..Net经典面试题目及答案[zt] 本文集中了多条常见的C#..Net经典面试题目例如".NET中类和结构的区别"."ASP.NET页面之间传递值的几种方式? ...

  6. 33条C#、.Net经典面试题目及答案[zt]

    33条C#..Net经典面试题目及答案[zt] 本文集中了多条常见的C#..Net经典面试题目例如“.NET中类和结构的区别”.“ASP.NET页面之间传递值的几种方式?”,并简明扼要的给出了答案,希 ...

  7. 特级教师总结的教育之33条(ZZ)

    一位班主任发给家长的一则短信:“无论成绩好坏,请想想:每个孩子都是种子,只不过每个人的花期不同.有的花,一开始就灿烂绽放:有的花,需要漫长的等待.不要看着别人怒放了,自己的那棵还没有动静就着急,相信是 ...

  8. 33条C#和.NET经典面试题目及答案

    1. .NET中类和结构的区别? 答:结构和类具有大体的语法,但是结构受到的限制比类要多. a. 结构不能有默认的构造函数,因为结构的副本是用编译器创建和销毁的,所以不需要默认的构造函数和析构函数. ...

  9. mysql索引合并:一条sql可以使用多个索引

    前言 mysql的索引合并并不是什么新特性.早在mysql5.0版本就已经实现.之所以还写这篇博文,是因为好多人还一直保留着一条sql语句只能使用一个索引的错误观念.本文会通过一些示例来说明如何使用索 ...

随机推荐

  1. 使用ApplicationLoader中出现报错:The IPA is invalid. It does not inlude a Payload directory

    问题处理方法: 1.将achieve的.app后缀的软件包放在一个payload的文件夹中 2.压缩该文件夹,改变.zip后缀为.ipa 3.使用applicationLoader上传该文件  

  2. Fixed theorems

    Banach Schauder Bourbaki-Kneser

  3. Nape的回调系统 nape.callbacks

    在Nape中增加一个回调大致分为三步 1:定义一些标签,并根据需求为不同的Interactor打上不同的标签 2:定义一个监听器,这个监听器定义了哪些标签触发了哪种行为之后做何种回调 3:为Space ...

  4. Ubuntu安装和配置redis

    1.用root用户登录 2.执行 sudo apt-get install redis-server 部分截图

  5. Android 如何修改默认的searchable items。

    前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net        ...

  6. Android Studio导入项目

    原文:http://ask.android-studio.org/?/article/21 本篇教程中使用到的Android Studio版本为1.0, Eclipse ADT版本23.0.4.请尝试 ...

  7. 新闻客户端nices

    https://github.com/android-cjj/nices

  8. jquery插件开发(checkbox全选的简单实例)

    html代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  9. air 中的 LocalStore

    <ignore_js_op> 在AIR客户端程序中有时需要将用户的一些信息保存在本地,如果信息没有涉及到隐私那么一般用SharedObject类即可将数据存储在本地.由于SharedObj ...

  10. 【ZT】修复iCloud中查找我的iPhone、查找我的iPad无法显示地图的方法

    http://blog.sina.com.cn/s/blog_4ff28d30010118cm.html 进入C:\Windows\System32\drivers\etc在hosts文件里加入如下地 ...