第33条:用EnumMap代替序数索引
有时候,会见到利用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代替序数索引的更多相关文章
- Effective Java 第三版——37. 使用EnumMap替代序数索引
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 用EnumMap代替序数索引
用EnumMap代替序数索引 有时候,会见到利用ordinal方法来索引数组的代码.例如下面这个简化的类,表示一种烹饪用的香草: public class Herb { public enum T ...
- 【Effective Java】9、使用EnumMap代替序数索引
package cn.xf.cp.ch02.item33; import java.util.EnumMap; import java.util.HashSet; import java.util.M ...
- 使用 ENUMMAP 替代序数索引
import java.util.Arrays; import java.util.EnumMap; import java.util.HashSet; import java.util.Map; i ...
- 33条C#、.Net经典面试题目及答案
33条C#..Net经典面试题目及答案[zt] 本文集中了多条常见的C#..Net经典面试题目例如".NET中类和结构的区别"."ASP.NET页面之间传递值的几种方式? ...
- 33条C#、.Net经典面试题目及答案[zt]
33条C#..Net经典面试题目及答案[zt] 本文集中了多条常见的C#..Net经典面试题目例如“.NET中类和结构的区别”.“ASP.NET页面之间传递值的几种方式?”,并简明扼要的给出了答案,希 ...
- 特级教师总结的教育之33条(ZZ)
一位班主任发给家长的一则短信:“无论成绩好坏,请想想:每个孩子都是种子,只不过每个人的花期不同.有的花,一开始就灿烂绽放:有的花,需要漫长的等待.不要看着别人怒放了,自己的那棵还没有动静就着急,相信是 ...
- 33条C#和.NET经典面试题目及答案
1. .NET中类和结构的区别? 答:结构和类具有大体的语法,但是结构受到的限制比类要多. a. 结构不能有默认的构造函数,因为结构的副本是用编译器创建和销毁的,所以不需要默认的构造函数和析构函数. ...
- mysql索引合并:一条sql可以使用多个索引
前言 mysql的索引合并并不是什么新特性.早在mysql5.0版本就已经实现.之所以还写这篇博文,是因为好多人还一直保留着一条sql语句只能使用一个索引的错误观念.本文会通过一些示例来说明如何使用索 ...
随机推荐
- 安卓开发21:深入理解Handler
Handler相关说明: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释:安卓的UI线程(即OnCreate函数创建的线程)是线程非安全的.也就是说,在UI线程中,使用sleep这样 ...
- Qt界面设计1
最近刚接触Qt 对于QML做界面感觉已经很轻松了,但是想尝试一下GUI..准备做一个理财的小软件 ....慢慢记录我的一点一滴的学习经历. 自己封装界面UI 遇到了好多新手级别的问题=_=!!! 1. ...
- 杭电 2602 Bone Collector
Bone Collector Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- MySQL 性能监控 4 大指标
[编者按]本文作者为 John Matson,主要介绍 mysql 性能监控应该关注的 4 大指标. 文章系国内 ITOM 管理平台 OneAPM 编译呈现. MySQL 是什么? MySQL ...
- java_jdbc_可滚动结果集与分页
public static void create2(int i) { Connection conn = null; Statement st = null; ResultSet rs = null ...
- USB HID usage table
This usage table lets usbhidctl decode the HID data correctly for the APC RS/XS1000's. This work was ...
- Servlet, Listener 、 Filter.
Java Web的三大组件:Servlet, Listener . Filter. 使用Listener监听器:八大监听器: 第一组:用于监听Servlet三个域对象的创建与销毁 1. Servlet ...
- 求教jsp 问题,能在一台电脑上运行,不能在另外一台上运行?
package com.mvc; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.se ...
- 简书APP
找第三方的时候看到简书这个APP,上网搜了一下发现网页版非常的干净,开头的一篇文章就是"你没实力就别心存侥幸",看完也挺有有同感的.文章网址:http://www.jianshu. ...
- 寻找对象在父元素下的index
方法一. window.onload=function(){ //寻找对象在父元素下的index function getIndexParent(element){ var ...