代碼審查的那些事兒

優(yōu)秀的代碼是優(yōu)秀應用的根基,通過代碼審查可以不斷的提高自己的代碼能力腹暖。但是提高這個事兒汇在,還是得思考的。

一脏答、isDebugEnabled()到底要不要

事情是這樣的糕殉,在使用sonar進行代碼檢查的時候,會提示你在調(diào)用日志組件時(日志等級為error以下)殖告,要預先判斷是否對應等級的日志打印功能是否開啟阿蝶,如下圖所示:

if (logger.isDebugEnabled()) {
    logger.debug(message);
}

很多文章都會提到這個問題,我也說下這個例子:

//早期的日志
logger.debug("error occurred:" + somMethod());

在這個語句中黄绩,無論debug是否開啟羡洁,待打印的內(nèi)容,包含字符串拼接和方法都會被執(zhí)行爽丹,在這種情況下筑煮,當debug等級日志為關(guān)閉的情況下,就存在性能消耗习劫。試想:日志內(nèi)容沒有打印出來,卻花了n秒來構(gòu)造參數(shù)嚼隘,是多么得不償失的诽里。
因此,sonar提示需要預先判斷飞蛹,用微小的損耗谤狡,換取系統(tǒng)可靠的保證,是很明智的卧檐。

很顯然墓懂,日志組件的開發(fā)們也發(fā)現(xiàn)了這樣的缺陷,他們也做了相應的改進:添加了字符串拼接功能

slf4j源碼片段
//改進后日志
logger.debug("error occurred:{}", description);

在執(zhí)行對應方法之前先執(zhí)行判斷霉囚,這樣就不會做無謂的字符串拼接工作了捕仔。但是,當參數(shù)是一個返回字符串的方法時,仍然無法避免對應方法的執(zhí)行榜跌。

顯而易見闪唆,需不需要isDebugEnabled()方法成了一個辯證的命題。

二钓葫、異常日志堆棧去哪兒了

這個事情是這樣的悄蕾,有一次線上環(huán)境出了問題,排查了一圈我除了異常類型和信息础浮,竟找不到任何異常的堆棧信息帆调,簡直是奇恥大辱啊。案發(fā)現(xiàn)場是這樣的:

//底下這個e是捕獲的異常
logger.error("error occurred...{}, {}", id, e)

為了防止這類慘案再次發(fā)生豆同,我去翻了源碼(使用的版本為slf4j-api 1.7.1番刊,源碼部分略),還做了一個實驗:

//先定義一個異常
Exception e = new RuntimeException("this is a runtime exception");

//情況1:給異常對象分配一個占位符
logger.debug("error occurred... {}, {}", "first string", e);

//調(diào)用異常對象的toString方法
logger.debug("error occurred... {}, {}", "third string", e.toString());

//未給異常對象分配占位符
logger.debug("error occurred... {}", "second string", e);

結(jié)果果然是還原了案發(fā)過程诱告,如下圖所示:情況1和2并沒有打印出異常的堆棧信息撵枢;在對于有占位符的參數(shù)對象,消息格式轉(zhuǎn)換會調(diào)用對象的toString()方法精居,所以說情況1和2是相同的锄禽。
在希望打印出異常堆棧的情況下(一般情況下,異常堆棧是需要的)靴姿,不要給Throwable參數(shù)添加字符串占位符{},否則不能如愿沃但。

前兩個日志結(jié)果打印

當然,我依然相信日志組件的開發(fā)們佛吓,肯定也會發(fā)現(xiàn)這樣的一個問題宵晚,于是嘗試了最新版本的日志,發(fā)現(xiàn)無論是否有占位符维雇,異常的堆棧信息都是能正常打印出來的淤刃。不過為了避免踩這個坑,還是建議大家注意占位符的問題吱型。

三逸贾、工具類的封裝

工具類是對通用方法的封裝,通過代碼復用來提高編程效率津滞。一般工具類的使用铝侵,都是只調(diào)用其方法,不涉及到類的任何屬性和變量触徐;因此我們看到的工具類中大都如下圖所示:

java.lang.Math 源碼
  • 私有的構(gòu)造方法
    工具類都是靜態(tài)方法咪鲜,無需實例化,有私有的構(gòu)造方法后撞鹉,程序就無法通過new Math()來實例化對象疟丙,要知道颖侄,實例化是有開銷的。
  • final修飾
    無法被繼承隆敢,其方法無法被重寫发皿。
    高效的內(nèi)聯(lián)調(diào)用(也有人說是內(nèi)嵌、inline)
  • 靜態(tài)的方法
    無法實例化拂蝎,肯定只能通過靜態(tài)方法來訪問了穴墅。
  • 職責單一 (面向?qū)ο蟮幕驹瓌t)
    在項目的代碼中見過這樣一個工具類:MyUtils.java。光看這個名字温自,肯定是不知道這個類是做什么用的玄货,看下實現(xiàn)的方法:
MyUtils.java的方法

簡單的對這些方法進行歸類:對象和Json對象的轉(zhuǎn)換、時間格式化悼泌、字符串操作松捉,這個類可以拆為三個工具類。

建議:多看看源碼馆里,積累工具類隘世,形成自己的工具類庫。

四鸠踪、線程安全對象的使用

線程安全和非線程安全的概念就不多贅述丙者,對于線程安全對象,肯定都非常熟悉营密,典型的是線程安全集合類:ConcurrentHashMap械媒、HashTable
舉個例子吧,由于String.java是final修飾的類评汰,造成了很多問題纷捞,其中就有一個字符串拼接的問題。在涉及大量字符串拼接方法中被去,直接使用"str1" + "str2"效率是極其低下的(是因為需要不斷的生成新的對象)主儡,這時候就需要借助StringBuilderStringBuffer。這兩個到底哪個是線程安全的呢惨缆?忘記了沒關(guān)系糜值,點開源碼看下說明就好了:

StringBuilder.java 源碼注釋

注釋說明了StringBuilder是非線程安全,而StringBuffer是線程安全的(多閱讀源碼踪央,養(yǎng)成依賴源碼而不是百度的習慣臀玄。對于會思考的程序員來說是大有裨益的)
只要判斷當前的場景瓢阴,是否需要線程安全就能夠合理的使用正確的對象了畅蹂。

案例一:

public String getXxxMessage(Xxx xxx){
    StringBuffer sb = new StringBuffer();    //在方法內(nèi)進行拼裝,應使用StringBuilder
    sb.append(xxx.getName).append("...")
    //省略部分代碼
    return sb.toString()
}

案例二:

//用內(nèi)存做緩存
private Map map = new ConcurrentHashMap();

public Object getCache(String key){
    ....
}

public void saveCache(Object o){
    ....
}

案例三:

//高并發(fā)場景
private Random random = new Random();

public Object saveXX(Xx x){
    int i = random.nextInt(10);   //高并發(fā)情況下存在鎖競爭引起線程阻塞荣恐,影響性能
    doSomething(i);
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末液斜,一起剝皮案震驚了整個濱河市累贤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌少漆,老刑警劉巖臼膏,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異示损,居然都是意外死亡渗磅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門检访,熙熙樓的掌柜王于貴愁眉苦臉地迎上來始鱼,“玉大人,你說我怎么就攤上這事脆贵∫角澹” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵卖氨,是天一觀的道長会烙。 經(jīng)常有香客問我,道長筒捺,這世上最難降的妖魔是什么柏腻? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮焙矛,結(jié)果婚禮上葫盼,老公的妹妹穿的比我還像新娘。我一直安慰自己村斟,他們只是感情好贫导,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蟆盹,像睡著了一般孩灯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逾滥,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天峰档,我揣著相機與錄音,去河邊找鬼寨昙。 笑死讥巡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的舔哪。 我是一名探鬼主播欢顷,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捉蚤!你這毒婦竟也來了抬驴?” 一聲冷哼從身側(cè)響起炼七,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎布持,沒想到半個月后豌拙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡题暖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年按傅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胧卤。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡逞敷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灌侣,到底是詐尸還是另有隱情推捐,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布侧啼,位于F島的核電站牛柒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏痊乾。R本人自食惡果不足惜皮壁,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哪审。 院中可真熱鬧蛾魄,春花似錦、人聲如沸湿滓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叽奥。三九已至扔水,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朝氓,已是汗流浹背魔市。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赵哲,地道東北人待德。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像枫夺,于是被迫代替她去往敵國和親将宪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關(guān)的語法涧偷,內(nèi)部類的語法,繼承相關(guān)的語法毙死,異常的語法燎潮,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,164評論 25 707
  • 假如生活欺騙了你,不要悲傷扼倘,不要心急……相信吧确封,明天也許會更難過! 以前吧再菊,生活不如意爪喘,咱就總愛喝點雞湯撫慰一下受...
    坍塌的迷墻閱讀 870評論 0 4
  • 少年,你可還記得已經(jīng)走出校門多久了纠拔?可曾記得這些年是如何摸爬滾打的秉剑?曾經(jīng)你是那個意氣風發(fā)的要仗劍走天涯,去看看這個...
    洪武先生閱讀 223評論 0 0
  • 今天主要學習了新的知識 MFC的應用 Windows運行的內(nèi)部原理稠诲,是一些理論知識侦鹏,了解一下windows編程的基...
    34d71ddb735c閱讀 60評論 0 0