[改善Java代码]推荐使用枚举定义常量
枚举和注解都是在Java1.5中引入的,虽然他们是后起之秀,但是功能不容小觑,枚举改变了常量的声明方式,注解耦合了数据和代码.
建议83:推荐使用枚举定义常量
一、分析
常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量。不过,在1.5版之后有了改进,即新增了一种常量声明方式,枚举常量。代码如下:
enum Season{
Spring,Summer,Autumn,Winter;
}
JLS(Java Language Specification,Java语言规范)提倡枚举项全都大写,字母之间用下划线分隔.这也是从常量的角度考虑的.
那么枚举常量与我们的经常使用的类常量和静态常量比有什么优势呢?
枚举的优点主要表现在以下四个方面.
1.枚举常量更简单
先把Season枚举翻译成接口,代码如下:
interface Season{
int Sprint = 0;
int Summer = 1;
int Autumn = 2;
int Winter = 3;
}
首先对比以下两者的定义,枚举常量只需要定义每个枚举项,不需要定义枚举值,而接口常量(或类常量)则必须定义值,否则编译通不过,即使我们不需要关注其值是多少也必须定义;其次,虽然两个引用的方式相同(都是“类名.属性”,如Season.Sprint),但是枚举表示的是一个枚举项,字面含义是春天,而接口常量却是一个int类型,虽然其字面含义也是春天,但在运算中我们势必要关注其int值.
2.枚举常量属于稳态型
例如:我们要给外星人描述一下地球上的春夏秋冬是什么样子的,使用接口常量应该是这样写.
public void describe(int s){
//s变量不能超越边界,校验条件
if(s >= 0 && s <4){
switch(s){
case Season.Summer:
System.out.println("Summer is very hot!");
break;
case Season.Winter:
System.out.println("Winter is very cold!");
break;
.....
}
}
}
我们需要用switch语句判断是哪一个常量,然后输出.但问题是我们得对输入值进行检查,确定是否越界,如果常量非常庞大,校验输入就是一件非常麻烦的事情,但这是一个不可逃避的过程,特别是如果我们的校验条件不严格,虽然可以编译照样通过,但是运行期就会产生无法预知的后果.
我们再来看看枚举常量是否能够避免校验问题,代码如下:
public void describe(Season s){
switch(s){
case Season.Summer:
System.out.println("Summer is very hot!");
break;
case Season.Winter:
System.out.println("Winter is very cold!");
break;
......
}
}
不用校验,已经限定了是Season枚举,所以只能是Season类的四个实例。这也是我们看重枚举的地方:在编译期间限定类型,不允许发生越界的情况。
3.枚举具有内置方法
有一个很简单的问题:如果要列出所有的季节常量,如何实现?接口常量或者类常量可以通过反射来实现,这没错,只是虽然能实现,但会非常繁琐.但是对于枚举就可以非常简单的实现.
public static void main(String[] args){
for(Season s:Season.values()){
System.out.println(s);
}
}
通过values()方法获得所有的枚举项.这得益于枚举内置的方法,每个枚举都是java.lang.Enum的子类,该基类提供了诸如获得排序值的ordinal方法、compareTo比较方法等,大大简化了常量的访问。
4.枚举可以自定义方法
这一点似乎不是枚举的优点,类常量也可以有自己的方法,但关键是枚举常量不仅仅可以定义静态方法,还可以定义非静态方法,而且还能够从根本上杜绝常量类被实例化。比如我们在定义获取最舒服的季节,使用枚举的代码如下:
enum Season{
Spring,Summer,Autumn,Winter;
//最舒服的季节
public static Season getComfortableSeason(){
return Spring;
}
}
我们知道每个枚举项都是该枚举的一个实例,对于我们的例子来说,也就表示Spring其实是Season的一个实例,Summer也是其中的一个实例.那我们再枚举中定义的静态方法既可以在类(Season类)中引用,也可以在实例(也就是枚举项Spring,Summer,Autumn,Winter)中引用,看如下代码:
enum Season{
Spring,Summer,Autumn,Winter;
//最舒服的季节
public static Season getComfortableSeason(){
return Spring;
}
}
public class Client {
public static void main(String[] args) {
System.out.println("The most comfortable season is " + Season.getComfortableSeason());
System.out.println("kxh test " + Season.getComfortableSeason());
}
}
那如果使用类常量要如何实现呢?代码如下:
class Season{
public final static int Spring = 0;
public final static int Summer = 1;
public final static int Autumn = 2;
public final static int Winter = 3;
//最舒服的季节
public static int getComfortableSeason(){
return Spring;
}
}
想想看,我们要怎么才能打印出"The most comfortable season is Spring" 这句话呢? 除了使用switch判断外没有其他更好的办法了.
虽然枚举在很多方面都比接口常量和类常量好用,但是它有一点比不上接口常量和类常量的,就是继承,枚举类型是不能有继承的,也就是说一个枚举常量定义完毕后,除非修改重构,否则无法做扩展。
三、建议
在项目开发中,推荐使用枚举常量代替接口常量或类常量。
[改善Java代码]推荐使用枚举定义常量的更多相关文章
- 拔高你的Java代码质量吧:推荐使用枚举定义常量(转)
提高你的Java代码质量吧:推荐使用枚举定义常量 一.分析 常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量.不过,在1.5版之后有了改进,即新增了一 ...
- [改善Java代码]推荐覆写toString方法
建议49: 推荐覆写toString方法 为什么要覆写toString方法,这个问题很简单,因为Java提供的默认toString方法不友好,打印出来看不懂,不覆写不行,看这样一段代码: public ...
- [改善Java代码]推荐使用String直接量赋值
建议52:推荐使用String直接量赋值 一.建议 String对象的生成方式有两种: 1.通过new关键字生成,String str3 = new String(“中国”); 2.直接声明,如:St ...
- [改善Java代码]推荐在复杂字符串操作中使用正则表达式
一.分析 字符串的操作,诸如追加.合并.替换.倒序.分隔等,都是在编码过程中经常用到的,而且Java也提供了append.replace.reverse.split等方法来完成这些操作,它们使用起来 ...
- [改善Java代码] 推荐使用序列化实现对象的拷贝
建议44: 推荐使用序列化实现对象的拷贝 上一个建议说了对象的浅拷贝问题,实现Cloneable接口就具备了拷贝能力,那我们来思考这样一个问题:如果一个项目中有大量的对象是通过拷贝生成的,那我们该如何 ...
- [改善Java代码]小心switch带来的空值异常
使用枚举定义常量时,会伴有大量的switch语句判断,目的是伪类每个枚举项解释其行为,例如: public class Client { public static void main(String[ ...
- 提高Java代码质量:使用枚举定义常量(转)
一.分析 常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量.不过,在1.5版之后有了改进,即新增了一种常量声明方式,枚举常量.代码如下: enum ...
- [改善Java代码]使用构造函数协助描述枚举项
一.分析 一般来说,我们经常使用的枚举项只有一个属性,即排序号,其默认值是从0.1.2... ....但是除了排序号外,枚举还有一个(或多个)属性:枚举描述,它的含义是通过枚举的构造函数,声明每个枚举 ...
- [改善Java代码]在switch的default代码块中增加AssertionError错误
switch的后跟枚举类型,case后列出所有的枚举项,这是一个使用枚举的主流写法,那留着default语句似乎没有任何作用了,程序已经列举出了所有的可能选项,肯定不会执行到default语句,. 错 ...
随机推荐
- Apache Spark Shark的简介
Shark是构建在Spark和Hive基础之上的数据仓库. 目前,Shark已经完成学术使命,终止开发,但其架构和原理仍具有借鉴意义. 它提供了能够查询Hive中所存储数据的一套SQL接口,兼容现有的 ...
- POJ 3169 Layout (差分约束系统)
Layout 题目链接: Rhttp://acm.hust.edu.cn/vjudge/contest/122685#problem/S Description Like everyone else, ...
- HDU 1272 小希的迷宫 (并查集)
小希的迷宫 题目链接: http://acm.hust.edu.cn/vjudge/contest/123393#problem/L Description 我们的小伙伴Bingo身为大二学长,他乐于 ...
- HDU 1068 Girls and Boys (二分图最大独立集)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1068 有n个同学,格式ni:(m) n1 n2 n3表示同学ni有缘与n1,n2,n3成为情侣,求集合 ...
- 模拟学信网登录,Cookie 序列化,在反序列化之后不能用的问题
昨天和今天在模拟学信网登录,然后抓取用户的信息数据的时候发现一直登录不成功, 登录页面,https://account.chsi.com.cn/passport/login?service=http% ...
- ags注册
在电脑里找到2个 ESRIRegAsm.exe C:\Program Files (x86)\Common Files\ArcGIS\bin C:\Program Files\Common Files ...
- 剑指OFFER之用两个栈实现队列(九度OJ1512)
题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作.队列中的元素为int类型. 输入: 每个输入文件包含一个测试样例.对于每个测试样例,第一行输入一个n(1<=n<=100 ...
- CentOS6.4 64位系统安装jdk
1. CentOS操作安装好了以后,系统自带了openJDK,先查看相关的安装信息: $rpm -qa | grep java tzdata-java-2013b-1.el6.noarchjava-1 ...
- SSL协议与数字证书原理
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- Transaction Manager Maximum Timeout
TransactionManager.MaximumTimeout是个只读的属性, 默认只有10分钟, 要想修改它必须通过machine.config来修改. 为了单个应用而去修改这个值是不合适的. ...