第30条:用enum代替int常量
在java1.5之前,表示枚举类型的常用模式是声明一组具名的int常量,每个类型成员一个常量:
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;
缺点:
1.将apple传到想要orange的方法中,不会出现错误
2.用==操作符将apple与orange比较,不会出现错误
3.int枚举是编译时常量,被编译到客户端中,如果枚举常量关联的int发生变化,客户端必须重新编译,如果没有重新编译,程序仍可以运行,但行为就确定了,如APPLE_FUJI关联的常量不再是0,而是3。
4.将int枚举常量翻译成可打印的字符串很麻烦
5.遍历一个组中所有的int枚举常量,获得int枚举组的大小,没有可靠的方法,如想知道APPLE的常量有多少个,除了查看int枚举常量所在位置的代码外,别无他法,而且靠的是观察APPLE_前缀有多少个,不可靠
枚举类型是int枚举常量的替代解决方案:
public enum Apple {FUJI, PIPPIN, GRANNY_SMITH}
public enum Orange {NAVEL, TEMPLE, BLOOD}
枚举是功能齐全的类,通过公有的静态final域为每个枚举常量导出实例的域。因为没有可以可以访问的构造器,客户端不能创建枚举类型的实例,也不能扩展它。
枚举提供编译时的类型安全,如果一个参数的类型是Apple,就可以保证,被传入到该参数上的任何非null对象引用一定是FUJI,PIPPIN,GRANNY_SMITH三个之一。
包含同名常量的多个枚举类型可以共存,因为每个类型有自己的命名空间,增加或重新排列枚举类型的常量,无需重新编译客户端代码。
通过调用toString方法,可以将枚举转换成可打印的字符串。
枚举类型有方法和域:
public enum Planet {
MERCURY(3.302e+23, 2.439e6),
VENUS(4.869e+24, 6.052e6),
EARTH(5.975e+24, 6.378e6),
MARS(6.419e+23, 3.393e6),
JUPITER(1.899e+27, 7.149e7),
SATURN(5.685e+26, 6.027e7),
URANUS(8.683e+25, 2.556e7),
NEPTUNE(1.024e+26, 2.477e7);
private final double mass;
private final double radius;
private final double surfaceGravity; private static final double G = 6.67300e-11; Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
surfaceGravity = G * mass / (radius * radius);
} public double mass() {
return mass;
} public double radius() {
return radius;
} public double surfaceGravity() {
return surfaceGravity;
} public double surfaceWeight(double mass) {//F=ma
return mass * surfaceGravity;
} }
根据某个物体在地球上的重量,显示该物体在所有8颗行星上的重量:
public static void main(String[] args) {
double earthWeight = 175;
double mass = earthWeight / Planet.EARTH.surfaceGravity();
for(Planet p : Planet.values()) {
System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
}
}
如果枚举具有普遍适用性,它应该成为一个顶层类,如果只被用在一个特定的顶层类中,应该成为顶层类的一个成员类。
java.math.RoundingMode枚举表示十进制的舍入模式,用在BigDecimal类。
Planet示例展示每个常量关联不同的数据,有时候需要将本质上不同的行为与常量关联起来。
假设有一个枚举类型,表示计算器的四大基本操作:
public enum Operation {
PLUS("+") {
double apply(double x, double y) {return x + y;}
},
MINUS("-") {
double apply(double x, double y) {return x - y;}
},
TIMES("*") {
double apply(double x, double y) {return x - y;}
},
DIVIDE("/") {
double apply(double x, double y) {return x - y;}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
public String toString() {
return symbol;
}
abstract double apply(double x, double y);
}
某些情况下,覆盖toString方法使打印算术表达式很容易:
public static void main(String[] args) {
double x = 2.0;
double y = 4.0;
for(Operation op : Operation.values())
System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x,y));
}
枚举类型有一个自动产生的valueOf(String)方法,它将常量的名字转变成常量本身。
如果覆盖toString方法,要考虑编写一个fromString方法,将字符串表示法变回相应的枚举:
private static final Map<String, Operation> stringToEnum
= new HashMap<String, Operation>();
static {
for(Operation op : values())
stringToEnum.put(op.toString(), op);
}
public static Operation fromString(String symbol) {
return stringToEnum.get(symbol);
}
枚举策略解决多个枚举常量同时共享相同的行为。
加班报酬,weekday和weekend的计算方式不一样:
enum PayrollDay {
MONDAY(PayType.WEEKDAY),
THESDAY(PayType.WEEKDAY),
WEDNESDAY(PayType.WEEKDAY),
THURSDAY(PayType.WEEKDAY),
FRIDAY(PayType.WEEKDAY),
SATURDAY(PayType.WEEKEND),
SUNDAY(PayType.WEEKEND); private final PayType p;
PayrollDay(PayType p) {
this.p = p;
}
double pay(double hoursWorked, double payRate) {
return payType.pay(hoursWorked, payRate);
} private enum PayType {
WEEKDAY {
double overtimePay(double hours, double payRate) {
return hours <= HOURS_PER_SHIFT ? 0 :
(hours - HOURS_PER_SHIFT) * payRate * 2;
}
},
WEEKEND {
double overtimePay(double hours, double payRate) {
return hours * payRate / 2;
}
};
private final static int HOURS_PER_SHIFT = 8;
abstract double overtimePay(double hours, double Rate);
double pay(double hoursWorked, double payRate) {
double basePay = hoursWorked * payRate;
return basePay + overtimePay(hoursWorked, payRate);
}
}
}
每当需要一组固定常量的时候,就应该使用枚举。
第30条:用enum代替int常量的更多相关文章
- Item 30 用enum代替int常量类型枚举,string常量类型枚举
1.用枚举类型替代int枚举类型和string枚举类型 public class Show { // Int枚举类型 // public static final int APPLE_FUJI ...
- 用枚举enum替代int常量
枚举的好处: 1. 类型安全性 2.使用方便性 public class EnumDemo { enum Color{ RED(3),BLUE(5),BLACK(8),YELLOW(13),GREEN ...
- 分30条依次解析xml并插入数据库成功
package xxx; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import or ...
- 后端程序员必备:书写高质量SQL的30条建议
前言 本文将结合实例demo,阐述30条有关于优化SQL的建议,多数是实际开发中总结出来的,希望对大家有帮助. 1.查询SQL尽量不要使用select *,而是select具体字段. 反例子: sel ...
- enum和int、string的转换操作
enum Countries{ 中国 = 5, 美国, 俄罗斯, 英国, 法国} enum 和 int enum -> intint num = (int)Coun ...
- 写好Java代码的30条经验总结(转)
成为一个优秀的Java程序员,有着良好的代码编写习惯是必不可少的.下面就让我们来看看代码编写的30条建议吧. (1) 类名首字母应该大写.字段.方法以及对象(句柄)的首字母应小写.对于所有标识符,其中 ...
- C# enum、int、string三种类型互相转换
enum.int.string三种类型之间的互转 #代码: public enum Sex { Man=, Woman= } public static void enumConvert() { in ...
- 写好Java代码的30条经验总结
成为一个优秀的Java程序员,有着良好的代码编写习惯是必不可少的.下面就让我们来看看代码编写的30条建议吧. (1) 类名首字母应该大写.字段.方法以及对象(句柄)的首字母应小写.对于所有标识符,其中 ...
- 30条SQL查询优化原则
在我们平常的SQL查询中,其实我们有许多应该注意的原则,以来实现SQL查询的优化,本文将为大家介绍30条查询优化原则. 首先应注意的原则 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 wher ...
随机推荐
- Config the Android 5.0 Build Environment
In this document Choosing a Branch Setting up a Linux build environment Installing the JDK ...
- ADO.Net的小知识(连接数据库)
数据库连接分为两种,分别是断开式连接和打开式连接.下面分别和大家分享一下断开时连接的查询: (1)引入命名空间:using System.Data.SqlClient; 该语句用于导入和ADO.Net ...
- Locally Weighted Regression
简单回顾一下线性回归.我们使用了如下变量:\(x\)—输入变量/特征:\(y\)—目标变量:\((x,y)\)—单个训练样本:\(m\)—训练集中的样本数目:\(n\)—特征维度:\((x^{(i)} ...
- Windows7中Emacs 24 shell使用Gitbash
今天发现可以在shell中直接打开Gitbash,Gitbash提供了一些有用的Linux风格命令,最关键是我用emacs的时候不用再打开一个Gitbash终端操纵Git了. 在~/.emacs.d/ ...
- Using the EventManager
Using the EventManager This tutorial explores the features of zend-eventmanager in-depth. Terminolog ...
- linux 查看文件命令总结
linux 查看文件命令总结 1.cat 查看文件内容 选项-b 空白行不显示行号.-n,空白行显示 2.more 查看文件内容,通过空格键查看下一页 q键退出查看 3.less 和上同,多了方向键( ...
- Swift基础语法-内存管理, 自动引用计数
1. 工作机制 Swift和OC一样,采用自动引用计数来管理内存 当有一个强引用指向某一个对象时,该对象的引用计数会自动+1 当该强引用消失时,引用计数会自动-1 当引用计数为0时,该对象会被销毁 2 ...
- Flume简介与使用(三)——Kafka Sink消费数据之Kafka安装
前面已经介绍了如何利用Thrift Source生产数据,今天介绍如何用Kafka Sink消费数据. 其实之前已经在Flume配置文件里设置了用Kafka Sink消费数据 agent1.sinks ...
- 使用kdbg或nemiver调试ROS
Kdbg Kdbg是KDE环境下的一个gdb的前端GUI,使用起来比较友好,速度也很快,安装和使用请参考: http://www.kdbg.org/ 在UBUNTU下可以直接使用APT安装: sudo ...
- 关于HTML5标签不兼容(IE6~8)
HTML5的语义化标签以及属性,可以让开发者非常方便地实现清晰的web页面布局,加上CSS3的效果渲染,快速建立丰富灵活的web页面显得非常简单. 比较常用的HTML5的新标签元素有: <hea ...