java项目中常量规范定义的思考

大言不惭,则无必为之志。——《论语·宪问》

1、引言

最近在看老大在项目中写的代码,发现在系统常量的定义上,与我之前在开发项目的定义有些不一样,引发了我对系统变量如何规范定义和每一种定义有什么优点?这两个问题的好奇。

为什么需要定义常量?
提取常量主要是为了避免魔法数字和提高代码可读性保证一致性。

首先我想研究下,有哪几种定义常量的方法,经过谷歌,主要有两种:

  • (1)在接口中定义
public interface Constants {
    static final String URL = "http://baidu.com/";
}
  • (2)在类中定义
public class Constants {
    public final static String URL = "http://baidu.com/";
}

下面我们就先从这两种方式开始讨论,再去思考哪种方式更适合常量定义。

2、在接口中常量

public interface Constants {
    static final String URL = "http://baidu.com/";
}

为什么会在接口中定义常量?那是由于在java interface中声明的字段在编译时会自动加上static final的修饰符,即声明为常量。因而interface通常是存放常量的最佳地点。然而在java的实际应用时却可能会产生一些问题。

问题有两个,
(1)第一,是我们所使用的常量并不是一成不变的,而是相对于变量不能赋值改变。例如我们在一个工程初期定义常量∏=3.14,而由于计算精度的提高我们可能会重新定义∏=3.14159,此时整个项目对此常量的引用都应该做出改变。
(2)第二,java是动态语言。与c++之类的静态语言不同,java对一些字段的引用可以在运行期动态进行,这种灵活性是java这样的动态语言的一大优势。也就使得我们在java工程中有时部分内容的改变不用重新编译整个项目,而只需编译改变的部分重新发布就可以改变整个应用。

这部分的细节可参考:https://www.ibm.com/developerworks/cn/java/l-java-interface/index.html

另外,根据单一责任原则,因为接口定义出来主要是为了让其它类实现的,用不可继承且不能被外部实例化的类可以很好的保证常量的单一性。

3、在常量类中定义

public class Constants {
    public final static String URL = "http://baidu.com/";
}

常量定义在final的class中,防止被其它类继承和实例化。

在阿里巴巴Java开发手册中也对常量定义给出了规范:
1. 【强制】不允许任何魔法值(即未经定义的常量)直接出现在代码中。 反例:String key = “Id#taobao_” + tradeId;
cache.put(key, value);

2. 【强制】long 或者 Long 初始赋值时,使用大写的 L,不能是小写的 l,小写容易跟数字 1 混 淆,造成误解。
说明:Long a = 2l; 写的是数字的21,还是Long型的2?

3. 【推荐】不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。 说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。 正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 ConfigConsts 下。

4. 【推荐】常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包 内共享常量、类内共享常量。
1) 跨应用共享常量:放置在二方库中,通常是client.jar中的constant目录下。 2) 应用内共享常量:放置在一方库中,通常是modules中的constant目录下。
反例:易懂变量也要统一定义成应用内共享常量,两位攻城师在两个类中分别定义了表示 “是”的变量:
类A中:public static final String YES = “yes”;
类B中:public static final String YES = “y”; A.YES.equals(B.YES),预期是 true,但实际返回为 false,导致线上问题。
3) 子工程内部共享常量:即在当前子工程的constant目录下。
4) 包内共享常量:即在当前包下单独的constant目录下。
5) 类内共享常量:直接在类内部private static final定义。

5. 【推荐】如果变量值仅在一个范围内变化,且带有名称之外的延伸属性,定义为枚举类。下面 正例中的数字就是延伸信息,表示星期几。
正例:public Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);}

13.【推荐】接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁 性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是 与接口方法相关,并且是整个应用的基础常量。

4、推荐做法

public final class Constants {
    private Constants(){
    } 
    public static final String URL = "http://baidu.com/";
}

上面的写法主要考虑以下几点:
(1)class的类型为final,表示该类是不可以继承的;
(2)定义了一个私有的构造函数,避免实例化该类;
(3)常量的类型为public final static,static修饰的属性的初始化在编译期(类加载的时候),初始化后能改变。final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变。static修饰的属性强调它们只有一个,final修饰的属性表明是一个常数(创建后不能被修改)。修饰的属性表示一旦给值,就不可修改,并且可以通过类名访问;

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值