[改善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语句,. 错 ...
随机推荐
- homework08
1.局部变量生命周期 #include "iostream.h" ;} int main() { ; add1(n); cout << n << endl; ...
- 用一个例子学习CSS的伪类元素
CSS伪类元素是一个非常酷的东西!首先我们理解一下它,:before :after 伪类元素,也就是虚假的元素.它可以插入在元素的前面或者后面,而在HTML文档结构中,它却是不存在的,因为Js是无法通 ...
- [iOS UI进阶 - 3.1] 触摸事件的传递
A.事件的产生和传递 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发 ...
- [C语言 - 7] 结构体struct
A. 基本知识 与数组的对比 数组: 构造类型 只能有多个相同类型的数据构成 结构体: 结构体类型 可以由多个不同类型的数据构成 1. 定义类型 struct Student { int ...
- [转]ORA-00907: 缺失右括号
转至:http://www.cnblogs.com/Olive116/p/5149680.html ORA-00907: 缺失右括号 前言 最近在开发过程中使用oracle数据库,在程序中进行查询数据 ...
- 在Hibernate中使用HibernateTemplate来进行包含sql语句的查询
/** * 使用sql语句进行查询操作 * @param sql * @return */ public List queryWithSql(final Stri ...
- Squid 日志详解
原文地址: http://www.php-oa.com/2008/01/17/squid-log-access-store.html access.log 日志 在squid中access访问日志最为 ...
- 关于STM32的ST官方的库的一点看法
标题确实很别扭,因为我现在用这个库也很别扭. 在不久之前,一直有个讨论的话题:STM32开发是用库还是用寄存器? 很多人的结论是不需要讨论! 但是,今天我想说下我的看法. 首先,我还是一个菜鸟,对库对 ...
- Codeforces Round #185 (Div. 2) B. Archer 水题
B. Archer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/312/problem/B D ...
- ApiDemo/FragmentRetainInstance 解析
/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Versi ...