常量指的就是在其作用域中保持不變的量淑玫,一般使用final關(guān)鍵字來修飾客峭,
根據(jù)作用域的劃分,常量分為全局常量栓撞,類內(nèi)常量和局部常量。
全局常量:public static final
類內(nèi)常量:private static final
局部常量:final(方法內(nèi)部)
示例代碼:
package 常量魔法值與枚舉;
public class 三種常量 {
public static final String GLOBAL_CONSTANT="shared in global";//全局常量
public static final String CLASS_CONSTANT="shared in class";//類內(nèi)常量
public void f(String s) {
final String methodConstant="shared in method";//局部常量
}
public void g(final int b) {//局部常量
System.out.println(b);
//b=3;報錯常量不可被賦值
}
}
關(guān)于常量的命名碗硬,我們一般使用全大寫字母瓤湘,且單詞之間使用_來隔開。
因為常量的使用范圍經(jīng)常是全類甚至全局的恩尾,如果常量的命名讓人不知其意弛说,那么就會造成閱讀困難,這其中最常出現(xiàn)的問題就是魔法值翰意。
魔法值即“共識層面”的常量木人,直接以具體的數(shù)值或字符出現(xiàn)在代碼中。
如下程序所示:
int [] array = new int[20];
for (int i = 0; i < 20; i++){
System.out.print(array[i]);
}
上述例子中猎物,如果數(shù)組的聲明與for循環(huán)相隔比較遠虎囚,就很難知道 for循環(huán)里面的控制條件 i < 20 中 20 具體含義是什么。它是數(shù)組的長度呢蔫磨,還是根據(jù)需求定義的界限值呢淘讥?就搞不清楚。
魔法數(shù)值使代碼的可讀性大大下降堤如。而且蒲列,如果同樣的數(shù)值多次出現(xiàn)時,到底這些數(shù)值是不是帶有同樣的含義呢搀罢,誰也說不清楚蝗岖。另一方面,如果本來應(yīng)該使用相同數(shù)值的地方榔至,一旦用錯了抵赢,也很難發(fā)現(xiàn)。因此,我們應(yīng)極力避免使用魔法數(shù)值铅鲤。
解決辦法就是使用static final 定義常量或使用enum值
關(guān)于常量我們已經(jīng)說過了划提,下面我們來寫下枚舉怎么解決魔法值問題。
假如有如下場景邢享,我們需要向一個視頻網(wǎng)站上放上我們的教學視頻鹏往,但是我們想讓視頻分類,有些視頻可以被觀看骇塘,有些視頻不能被觀看伊履,剛投稿的視頻要進審核也不能觀看。
大概在最開始我們的代碼可以這樣寫
public void getOnlinePackageCourse(Long packageId,Long userId) {
if(packageId==3) {
logger.error("線下課程款违,無法線上觀看");
return;
}
//其他邏輯處理
PackageCourse online = PackageService.getByTeacherId(userId);
if(online.getPackageId == 2) {
logger.error("未審核課程");
return;
}
//其他邏輯處理
}
}
我們隨意的用魔法值2唐瀑,3來表示未審核課程和線下課程,兩個數(shù)字而已奠货,容易記憶介褥。但是除了2,3外递惋,還有1,4溢陪,5萍虽,6等表示其他類型的課程⌒握妫或許我們在開發(fā)中可以靠記憶來判斷和告知其他人杉编,這些數(shù)字代表什么,但是時間一長咆霜,總會出漏洞邓馒。
為此,我們重構(gòu)代碼蛾坯,示例如下:
public enum CourseTypeEnum {
/**
* 允許官方和講師創(chuàng)建和運營
*/
VIDEO_COURSE(1, "錄播課程"),
/**
* 只允許官方創(chuàng)建和運營光酣,初始化必須設(shè)置合理的報名人數(shù)上限
*
*/
LIVE_COURSE(2,"直播課程"),
/**
* 只允許官方創(chuàng)建和運營
*/
ODDLINE_COURSE(3,"線下課程");
private int seq;
private String desc;
private CourseTypeEnum(int seq, String desc) {
this.seq = seq;
this.desc = desc;
}
public int getSeq() {
return seq;
}
public String getDesc() {
return desc;
}
}
上面把課程分為了三種,枚舉類型是幾乎不會改變的全局常量脉课。
我們再把視頻分為新課程救军,未審核課程,審核通過倘零,審核不通過唱遭,以刪除等五種狀態(tài)。用常量來定義
public abstract class BaseCourseState {
public static final int NEW_COURSE = 1;
public static final int UNAUTHED_COURSE = 2;
public static final int PASSED_COURSE = 3;
public static final int NOT_PASSED_COURSE = 4;
public static final int DELETE_COURSE = 5;
}
經(jīng)過代碼重構(gòu)后呈驶,我們的代碼可讀性立刻有了明顯提升拷泽。
public void getOnlinePackageCourse(Long packageId,Long userId) {
if(packageId==CourseTypeEnum.OFFLINE_COURSE.getSeq()) {
logger.error("線下課程,無法線上觀看");
return;
}
//其他邏輯處理
//PackageCourse online = PackageService.getByTeacherId(userId);
if(online.getPackageId == BaseCourseState.UNAUTHED_COURSE) {
logger.error("未審核課程");
return;
}
//其他邏輯處理
}
代碼為什么不允許出現(xiàn)魔法值
即使類內(nèi)常量和局部變量當前只使用一次,也要賦予一個有意義的名稱司致,目的一是望文知義订晌,二是在后期多次使用時能做到值出同源。
以下為警示代碼:
String key="Id#taobao_"+tradeId;
cache.put(key,value);
上面是用魔法值來拼裝key蚌吸,這導致各個調(diào)用方到處復制粘貼字符串
Id#taobao_,終于有一天锈拨,一個粗心的程序員復制的時候少了_,
這個錯誤在測試沒有被發(fā)現(xiàn),因為緩存沒有命中羹唠,會自動訪問數(shù)據(jù)庫奕枢。在大促中,數(shù)據(jù)庫壓力急劇上升佩微,進而發(fā)現(xiàn)緩存全部失效缝彬,導致連接占滿,查詢變慢哺眯。