11個簡單的Java性能調(diào)優(yōu)技巧

作為開發(fā)人員我們都希望編寫的程序擁有最佳的性能走诞,但是這需要大量的經(jīng)驗和知識。優(yōu)化應(yīng)用程序以獲得最佳性能并非易事沟饥。有幾個易于遵循的建議和最佳實踐可幫助創(chuàng)建性能良好的應(yīng)用程序棺亭。

1.在知道必須優(yōu)化之前不要進行優(yōu)化

這可能是最重要的性能調(diào)優(yōu)技巧之一。你應(yīng)該遵循常見的最佳實踐并嘗試有效地實現(xiàn)你的用例弟劲。但這并不意味著你應(yīng)該在證明必要之前替換任何標準庫或構(gòu)建復雜的優(yōu)化祷安。

在大多數(shù)情況下,過早優(yōu)化會占用大量時間并使代碼難以閱讀和維護兔乞。更糟糕的是汇鞭,這些優(yōu)化通常不會帶來任何好處,因為你花費了大量時間來優(yōu)化應(yīng)用程序的非關(guān)鍵部分庸追。

那么霍骄,你如何證明你需要優(yōu)化某些東西?

首先淡溯,需要定義應(yīng)用程序代碼的速度读整,例如,通過指定所有API調(diào)用的最大響應(yīng)時間或要在指定時間范圍內(nèi)導入的記錄數(shù)咱娶。完成后,可以測量應(yīng)用程序的哪些部分太慢并需要進行改進米间。當你這樣做時,你應(yīng)該看看第二個提示豺总。

2.使用Profiler查找真正的瓶頸

在按照第一個建議并確定需要改進的應(yīng)用程序部分后车伞,請問自己從哪里開始?

我們可以通過兩種方式處理此問題:

  • 可以查看代碼喻喳,然后從看起來可疑的部分或認為可能會產(chǎn)生問題的部分開始另玖。
  • 或者使用分析器并獲取有關(guān)代碼的每個部分的行為和性能的詳細信息。

顯而易見表伦,基于探查器的方法可以更好地理解代碼的性能影響谦去,并使自己可以專注于最關(guān)鍵的部分。如果我們曾經(jīng)使用過探查器蹦哼,我們會記得在一些情況下鳄哭,對代碼的哪些部分產(chǎn)生了性能問題感到驚訝。

3.為整個應(yīng)用程序創(chuàng)建性能測試套件

這是另一個通用提示纲熏,可幫助你避免在將性能改進部署到生產(chǎn)后經(jīng)常發(fā)生的許多意外問題妆丘。你應(yīng)該始終定義一個性能測試套件來測試整個應(yīng)用程序,并在你進行性能改進之前和之后運行它局劲。

這些額外的測試運行將幫助你識別更改的功能和性能副作用勺拣,并確保你不會發(fā)送造成弊大于利的更新。如果你處理應(yīng)用程序的多個不同部分(如數(shù)據(jù)庫或緩存)使用的組件鱼填,這一點尤為重要药有。

4.首先解決最大的瓶頸問題

在創(chuàng)建測試套件并使用分析器分析應(yīng)用程序之后,你將獲得要解決的問題列表以提高性能。這很好愤惰,但它仍然沒有回答你應(yīng)該從哪里開始的問題苇经。你可以專注于快速獲勝,或從最重要的問題開始宦言。

從快速獲勝開始可能很誘人扇单,因為你很快就能展示出第一批結(jié)果。有時蜡励,可能有必要說服其他團隊成員或你的管理層令花,性能分析值得付出努力。

但總的來說凉倚,我建議從頂部開始,首先開始解決最重要的性能問題嫂沉。這將為你提供最大的性能提升稽寒,你可能不需要解決多個這些問題以滿足你的性能要求。

足夠的一般性能調(diào)整技巧趟章。讓我們仔細看看一些特定于Java的杏糙。

5.使用StringBuilder以編程方式連接字符串

在Java中連接String有很多不同的選項。例如蚓土,你可以使用簡單的++ =宏侍,舊的StringBufferStringBuilder

那么蜀漆,你更喜歡哪種方法谅河?

答案取決于連接String的代碼。如果你以編程方式向String添加新內(nèi)容确丢,例如绷耍,在for循環(huán)中,則應(yīng)使用StringBuilder鲜侥。它易于使用褂始,并提供比StringBuffer更好的性能。但請記住描函,與StringBuffer相比崎苗,StringBuilder不是線程安全的,可能不適合所有用例舀寓。

你只需要實例化一個新的StringBuilder并調(diào)用append方法向String添加一個新的部分胆数。當你添加了所有部分時,可以調(diào)用toString()方法來檢索連接的String基公。

以下代碼段顯示了一個簡單示例幅慌。在每次迭代期間,此循環(huán)將i轉(zhuǎn)換為String并將其與空格一起添加到StringBuilder sb中轰豆。因此胰伍,最后齿诞,此代碼將“This is a test0 1 2 3 4 5 6 7 8 9”寫入日志文件。

StringBuilder sb = new StringBuilder(“This is a test”);
for (int i=0; i<10; i++) {
    sb.append(i);
    sb.append(” “);
}
log.info(sb.toString());

正如你在代碼片段中看到的骂租,你可以將String的第一個元素提供給構(gòu)造函數(shù)方法祷杈。這將創(chuàng)建一個新的StringBuilder,其中包含提供的String和16個附加字符的容量渗饮。當你向StringBuilder添加更多字符時但汞,你的JVM將動態(tài)增加StringBuilder的大小。

如果你已經(jīng)知道String將包含多少個字符互站,則可以將該數(shù)字提供給不同的構(gòu)造函數(shù)方法私蕾,以實例化具有已定義容量的StringBuilder。這進一步提高了效率胡桃,因為它不需要動態(tài)擴展其容量踩叭。

6.使用+在一個語句中連接字符串

當你使用Java實現(xiàn)第一個應(yīng)用程序時,有人可能會告訴你不應(yīng)該使用+連接String。如果你在應(yīng)用程序邏輯中連接String,這是正確的淹接。字符串是不可變的,每個字符串連接的結(jié)果都存儲在一個新的String對象中斤富。這需要額外的內(nèi)存并減慢你的應(yīng)用程序,特別是如果你在循環(huán)中連接多個String锻狗。

在這些情況下满力,你應(yīng)該遵循5號提示并使用StringBuilder

但是屋谭,如果你只是將String分成多行來提高代碼的可讀性脚囊,情況并非如此。

Query q = em.createQuery(“SELECT a.id, a.firstName, a.lastName ”
+ “FROM Author a ”
+ “WHERE a.id = :id”);

在這些情況下桐磁,你應(yīng)該將String與一個簡單的+連接起來悔耘。你的Java編譯器將對此進行優(yōu)化并在編譯時執(zhí)行串聯(lián)。因此我擂,在運行時衬以,你的代碼將只使用1個字符串,并且不需要連接校摩。

7.盡可能使用基元

另一種避免任何開銷和提高應(yīng)用程序性能的快捷方法是使用原始類型而不是它們的包裝類看峻。因此,最好使用int而不是Integer衙吩,或者使用double而不是Double互妓。這使你的JVM 的值存儲在堆棧,而不是堆的,以減少內(nèi)存消耗和整體更有效地處理它冯勉。

8.盡量避免使用BigInteger和BigDecimal

由于我們已經(jīng)在談?wù)摂?shù)據(jù)類型澈蚌,我們還應(yīng)該快速瀏覽一下BigIntegerBigDecimal。特別是后者因其精確性而受歡迎灼狰。但這需要付出代價宛瞄。

BigIntegerBigDecimal需要比簡單的longdouble更多的內(nèi)存,并且顯著減慢所有計算速度交胚。因此份汗,如果你需要額外的精度,或者如果你的數(shù)字將超過的范圍蝴簇,最好三思而后行杯活。這可能是你需要更改以修復性能問題的唯一方法,尤其是在你實施數(shù)學算法時熬词。

9.首先檢查當前日志級別

這個建議應(yīng)該是顯而易見的轩猩,但不幸的是,你可以找到許多忽略它的代碼荡澎。在創(chuàng)建調(diào)試消息之前,應(yīng)始終先檢查當前日志級別晤锹。否則摩幔,你可能會創(chuàng)建一個包含 日志消息String,之后將被忽略鞭铆。

以下是你不應(yīng)該這樣做的兩個示例或衡。

// 不能這樣寫
log.debug(“User [” + userName + “] called method X with [” + i + “]”);
//也不能這樣寫
log.debug(String.format(“User [%s] called method X with [%d]”, userName, i));

在這兩種情況下,你將執(zhí)行所有必需的步驟來創(chuàng)建日志消息车遂,而無需知道你的日志記錄框架是否將使用日志消息封断。在創(chuàng)建調(diào)試消息之前,最好先檢查當前日志級別舶担。

if (log.isDebugEnabled()) {
    log.debug(“User [” + userName + “] called method X with [” + i + “]”);
}

10.使用Apache Commons StringUtils.Replace而不是String.replace

通常坡疼,String.replace方法工作正常并且效率很高,特別是如果你使用的是Java 9.但是如果你的應(yīng)用程序需要大量的替換操作并且你還沒有更新到最新的Java版本衣陶,那么它仍然有意義檢查更快柄瑰,更有效的替代品。

一個候選人是 Apache Commons Lang的StringUtils.replace方法剪况。正如Lukas Eder在 他最近的一篇博客文章中所描述的那樣教沾,它顯著優(yōu)于Java 8的String.replace方法

它只需要一個微小的變化译断。你需要將Apache的Commons Lang項目的Maven依賴項添加到應(yīng)用程序pom.xml中授翻,并使用StringUtils.replace方法替換String.replace方法的所有調(diào)用。

// 這個寫法換成下面的寫法
test.replace(“test”, “simple test”);
// 替換寫法
StringUtils.replace(test, “test”, “simple test”);

11.緩存昂貴的資源,就像數(shù)據(jù)庫連接一樣

緩存是一種流行的解決方案堪唐,可以避免重復執(zhí)行昂貴或經(jīng)常使用的代碼片段巡语。一般的想法很簡單:重復使用這些資源比一次又一次地創(chuàng)建新資源要便宜。

典型示例是緩存池中的數(shù)據(jù)庫連接羔杨。創(chuàng)建新連接需要時間捌臊,如果重用現(xiàn)有連接,則可以避免這種情況兜材。

你還可以在Java語言本身中找到其他示例理澎。例如,Integer類的valueOf方法將值緩存在-128和127之間曙寡。你可能會說新的Integer的創(chuàng)建不是太昂貴糠爬,但是經(jīng)常使用它來緩存最常用的值提供性能優(yōu)勢。

但是當你考慮緩存時举庶,請記住你的緩存實現(xiàn)也會產(chǎn)生開銷执隧。你需要花費額外的內(nèi)存來存儲可重用資源,并且可能需要管理緩存以使資源可訪問或刪除過時的資源户侥。

因此镀琉,在開始緩存任何資源之前,請確保經(jīng)常使用它們來超過緩存實現(xiàn)的開銷蕊唐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屋摔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子替梨,更是在濱河造成了極大的恐慌钓试,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件副瀑,死亡現(xiàn)場離奇詭異弓熏,居然都是意外死亡,警方通過查閱死者的電腦和手機糠睡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門挽鞠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铜幽,你說我怎么就攤上這事滞谢。” “怎么了除抛?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵狮杨,是天一觀的道長。 經(jīng)常有香客問我到忽,道長橄教,這世上最難降的妖魔是什么清寇? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮护蝶,結(jié)果婚禮上华烟,老公的妹妹穿的比我還像新娘。我一直安慰自己持灰,他們只是感情好盔夜,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堤魁,像睡著了一般喂链。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妥泉,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天椭微,我揣著相機與錄音,去河邊找鬼盲链。 笑死蝇率,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的刽沾。 我是一名探鬼主播本慕,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼侧漓!你這毒婦竟也來了间狂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤火架,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后忙菠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體何鸡,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年牛欢,在試婚紗的時候發(fā)現(xiàn)自己被綠了骡男。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡傍睹,死狀恐怖隔盛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拾稳,我是刑警寧澤吮炕,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站访得,受9級特大地震影響龙亲,放射性物質(zhì)發(fā)生泄漏陕凹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一鳄炉、第九天 我趴在偏房一處隱蔽的房頂上張望杜耙。 院中可真熱鬧,春花似錦拂盯、人聲如沸佑女。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽团驱。三九已至,卻和暖如春榕订,著一層夾襖步出監(jiān)牢的瞬間店茶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工劫恒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贩幻,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓两嘴,卻偏偏與公主長得像丛楚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子憔辫,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

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

  • 大多數(shù)開發(fā)人員理所當然地以為性能優(yōu)化很復雜趣些,需要大量的經(jīng)驗和知識。好吧贰您,不能說這是完全錯誤的坏平。優(yōu)化應(yīng)用程序以獲得最...
    小宇java閱讀 351評論 0 0
  • 大多數(shù)開發(fā)人員理所當然地以為性能優(yōu)化很復雜,需要大量的經(jīng)驗和知識锦亦。好吧舶替,不能說這是完全錯誤的。優(yōu)化應(yīng)用程序以獲得最...
    java部落閱讀 233評論 0 1
  • 上周參加了家庭教育指導師的三天培訓杠园,感觸蠻多顾瞪,尤其是各位媽媽的分享,給我以后育兒提前做了預警抛蚁。 一棵樹搖動了另一棵...
    量子502閱讀 299評論 1 3
  • 收貨滿滿的一天陈醒,刷新了我對自己的認知,原來我也有愛看書的日子瞧甩。曾經(jīng)的我是那么的不愛看書钉跷,不管是考試類書集,亦或是詩...
    麗麗成長日記閱讀 208評論 0 1
  • 每次一回到家鄉(xiāng)肚逸,那種想要奮發(fā)向上的斗志就如同雜草般瘋狂的生長尘应,生生不息惶凝。 每一次一回到工作,學習的地方犬钢,那種去如雜...
    不飛翔不墮落閱讀 152評論 0 1