Java EnumMap 代替序数索引
2023-09-11 14:22:55 时间
学习笔记《Effective Java 中文版 第2版》
经常会碰到使用Enum的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;
}
}
现在假设有一个香草的数组,表示一座花园中的植物,你想要按照类型(一年生、多年生或者两年生植物)进行组织之后再将这些植物列出来。如果要这么做的话,需要构建三个集合,每种类型一个,并且遍历整座花园,将每种香草放到相应的集合中。有些程序员会将这些集合放到一个按照类型的序数进行索引的数组来实现这一点。
//Using ordinal() to index an array - DON'T DO THIS
Herb[] garden = ... ;
//Indexed by Herb.Type.ordinal()
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);
}
//Print the results
for(int i=0; i<herbsByType.length; i++) {
System.out.printf("%s: %s%n", Herb.Type.values()[i], herbsByType[i]);
}
这种方法的确可行,但是隐藏着许多问题。因为数组不能与泛型兼容。程序需要进行未受检的转换,并且不能正确无误地进行编译。因为数组不知道它的索引代表着什么,你必须手工标注这些索引的输出。但是这种方法最严重的问题在于,当你访问一个按照枚举的序数进行索引的数组时,使用正确的int值就是你的职责了;int不能提供枚举的类型安全。你如果使用了错误的值,程序就会悄然地完成错误的工作,或者幸运的话就会抛出ArrayIndexOutOfBoundException异常。
java.util.EnumMap是一种非常快速的Map实现专门用于枚举的键。
//Using an EnumMap to associate data with an enum
Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.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在运行速度方面之所以能与通过序数索引的数组相媲美,是因为EnumMap在内部使用了这种数组。但是它对程序员隐藏了这种思想细节,集Map的丰富功能和类型安全与数组的快速于一身。注意EnumMap构造器采用键类型的Class对象:这是一个有限制的类型令牌(bounded type token),它提供了运行时的泛型信息。
相关文章
- 7.java 加解密技术系列之 AES
- java的jdbc简单封装
- java - 详解 Java 17 中新推出的密封类
- 大杂烩 -- Java内存布局【图】以及java各种存储区【详解】
- Java Date Time 教程-java.sql.Timestamp
- Java基本数据类型包装类
- [转]java.sql.SQLException: 无效的列索引
- Ubuntu安装java的几种方式以及多个JAVA版本的切换
- 肝了!一篇文章搞定1000道大厂Java面试题
- 最新秋招,Java八股文!含答案,JAVA核心知识点最详细版(面试必备)
- 10个艰难的Java面试题与答案
- 【Java】java的内存浅析
- 哈弗曼编码与反编码的实现 java源代码
- maven项目的java和resources等文件夹不在Java Resources的文件夹里,并且缺少Deployment...
- Java 设计模式之装饰模式,Java 装饰模式,java装饰模式和代理模式的区别
- Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,java 判断请求是不是ajax请求
- Elasticsearch Java REST Client 初始化、添加索引及数据
- 在java中使用JMH(Java Microbenchmark Harness)做性能测试
- java中的hashCode
- 「Java 数据结构」:环形链表和约瑟夫问题。
- jsp头部报错:The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
- 浅析Java中不使用的对象应赋值为null的深层理解:基本没必要的原因、JVM中局部变量表(运行时候的栈状态)和slot(运行时栈里的索引)的理解、Java的栈优化(重用栈索引节约内存空间)、GC的可达性分析算法-如何找到root树根(栈中引用的对象)、如何断开栈中引用与堆的联系(重写栈索引)
- Java编程常用数据转换:String与int互转、Date与String互转、BigDecimal与int比较(报错operator > cannot be applied to java.math.BigDecimal,int)
- JAVA学习.java.sql.date 与java.util.date以及gettime()方法的分析
- 华为OD机试 -入栈出栈(Java) | 机试题+算法思路+考点+代码解析 【2023】
- 华为OD机试 - 按身高和体重排队(Java) | 机试题+算法思路+考点+代码解析 【2023】
- 【Harmony OS】【JAVA UI】鸿蒙怎么实现无限轮播功能
- 【JAVA】List中存放若干学生对象(学生有学号,姓名,性别等属性),去除List中重复的元素,并按学号降序输出。
- Java精确截取字符串