序,前言
重視代碼
facebook把code review作為重點KPI考核裙犹,并采用連坐制雌续。
code wins argument
當兩人為一個問題爭執(zhí)不下時桌吃,不妨以最快的速度用代碼把想法寫出來,事實勝于雄辯。代碼是負債不是資產(chǎn)
代碼越多,維護所要付出的成本就越高琅坡。
如果代碼結(jié)構(gòu)越好悉患,做了越多單元測試残家,代碼質(zhì)量越好、越小售躁、耦合越松坞淮,那么添加新代碼付出的成本就越少。本書觀點:代碼質(zhì)量與整潔度成正比
一陪捷,整潔代碼
糟糕混亂的代碼給項目帶來的負面影響
略過回窘。什么是整潔代碼
關(guān)鍵字: 只做好一件事,簡單直接市袖,意圖明確啡直,單元測試,盡量少的依賴關(guān)系苍碟,看起來像是專門解決那個問題而存在酒觅。破窗理論和童子軍軍規(guī)
第一扇窗被打破,但是沒有人管微峰,接下來會有更多的窗被打破舷丹,爛代碼不去管它只會越來越爛。
當你離開一個地方時蜓肆,要讓它比你來之前更干凈颜凯。代碼要易讀
我們編寫代碼時,讀和寫花費的時間比例超過10:1仗扬,要想代碼易寫症概,首先做到易讀。面向?qū)ο笤O(shè)計的原則(SOLID)
單一職責原則
開閉原則
里氏代換原則
接口隔離原則
依賴倒置原則
二早芭,有意義的命名
名副其實:為變量或函數(shù)起一個能反映其含義的名字并不容易彼城,但起名字花的時間是值得的,好的命名能讓讀者快速理解代碼,減少維護成本精肃。這和TDD四原則里的“揭示意圖”是一致的秤涩。
-
作者詳細介紹了命名需要注意的問題,
naming.PNG
結(jié)合我們的項目司抱,印象比較深的是“每個概念對應(yīng)一個詞”筐眷。
項目代碼中通常會有一些特定職責的類,xxxHandler, xxxManager, xxxProcessor, xxxBuilder, xxxHelper... 這樣的類名含義模糊习柠,令人費解匀谣,而這些類往往在做類似的事情。
三资溃,函數(shù)的原則
短小
if武翎、else、while語句內(nèi)的代碼塊應(yīng)該只有一行溶锭,該行大抵是一個函數(shù)調(diào)用語句宝恶。
這樣的函數(shù)不僅能保持短小,而且調(diào)用的函數(shù)具有說明性的名稱趴捅,從而增加了文檔上的價值垫毙。
所以函數(shù)的縮進不能多于兩層。只做一件事
寫函數(shù)是為了把大一些的概念(換言之拱绑,函數(shù)名稱)拆分為另一抽象層上的一系列步驟综芥。
判斷函數(shù)是否不止做了一件事,還有一個辦法就是看是否還能再拆出一個函數(shù)猎拨。每個函數(shù)一個抽象層級
要讓代碼有自頂向下的閱讀順序膀藐,向下規(guī)則:每個函數(shù)后面跟著下一抽象層級的函數(shù)。Switch語句
問題:太長红省,做了不止一件事额各,違反單一職責原則,違反開閉原則类腮,到處存在類似結(jié)構(gòu)的函數(shù)臊泰。
解決方案:把switch語句放在工廠類,使用接口多態(tài)的接受派遣蚜枢。使用描述性的名稱
函數(shù)越短小缸逃,功能越集中,越便于取個好名字厂抽。函數(shù)參數(shù)
- 參數(shù)越少越好需频,參數(shù)超過三個時,排序筷凤、琢磨昭殉、忽略的問題都會加倍體現(xiàn)苞七。
- 一元函數(shù)的普遍形式:A.操作參數(shù),轉(zhuǎn)換挪丢,返回蹂风。B.傳入event事件。
- 參數(shù)過多乾蓬,最好先封裝成類再傳入惠啄。
- 避免使用標識參數(shù),傳入true/false任内,明顯違反“只做一件事”的原則撵渡。
- 避免使用輸出參數(shù),如果要修改對象的狀態(tài)死嗦,要調(diào)用對象自己的函數(shù):
appendFooter(report);
應(yīng)該改成
report.appendFooter();
- 分隔指令與詢問
public boolean set(String attribute, String value);
該函數(shù)設(shè)置某個屬性的值趋距,如果設(shè)置成功返回true,如果不存在這個屬性返回false越除。
就會導(dǎo)致以下語句出現(xiàn):
if (set("userName", "Leo")) {...}
應(yīng)該改成
if (attributeExists("userName")) {
set("userName", "Leo")
}
-
使用異常替代返回錯誤碼
從指令式函數(shù)返回Error Code节腐,輕微違反了指令與詢問分隔的原則,而且導(dǎo)致更深層次的嵌套結(jié)構(gòu)廊敌。使用異常铜跑,錯誤處理代碼就能從主路徑代碼中分離出來门怪,得到簡化骡澈。
if (deletePage(page) == E_OK) {
if (registry.deleteReference(page.name) == E_OK) {
if (configKeys.deleteKey(page.name.makeKey()) == E_OK){
logger.log("page deleted");
} else {
logger.log("configKey not deleted");
}
} else {
logger.log("deleteReference from registry failed");
}
} else {
logger.log("delete failed");
return E_ERROR;
}
改成
try {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
} catch (Exception e) {
logger.log(e.getMessage());
}
try/catch代碼塊違反了只做一件事的原則,應(yīng)該把try和catch代碼塊主體部分抽出來掷空,另外形成函數(shù)
public void delete(Page page) {
try {
deletePageAndAllReferrence(page);
} catch (Exception e) {
logError(e);
}
}
private void deletePageAndAllReferrence(Page page) {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
private void logError(Exception e) {
logger.log(e.getMessage());
}
別重復(fù)自己
結(jié)構(gòu)化編程
只要函數(shù)保持短小肋殴,循環(huán)偶爾出現(xiàn)return, break, continue沒有問題,避免使用goto坦弟。函數(shù)修改的策略
對于冗長復(fù)雜的函數(shù)护锤,先加單元測試覆蓋每行丑陋的代碼,然后分解函數(shù)酿傍、修改名稱烙懦、消除重復(fù),同時保持單元測試通過赤炒。
小結(jié)
函數(shù)是動詞氯析,類是名稱,編程藝術(shù)是語言設(shè)計的藝術(shù)莺褒。大師級程序員把系統(tǒng)當成故事來講掩缓,而不是當作程序來寫。
四遵岩、注釋
當我們無法用代碼表達意圖時才使用注釋你辣。盡量避免使用注釋,用代碼表達意圖。
五舍哄、格式
- 格式的目的
- 代碼格式關(guān)乎溝通宴凉。
- 代碼風格和可讀性仍會影響到可維護性和擴展性。
- 垂直格式
- 短文件通常比長文件易于理解表悬,盡量短小而精悍跪解。
- 概念間垂直方向上的區(qū)隔,不同的思路段落之間用空白行隔開签孔,例如單元測試中的Given叉讥、When、Then用空白行隔開饥追。
- 垂直方向上图仓,關(guān)系密切的概念應(yīng)該相互靠近。
- 垂直順序但绕,被調(diào)用的函數(shù)應(yīng)該放在執(zhí)行調(diào)用的函數(shù)下面救崔。
- 橫向格式
- 水平方向的區(qū)隔和靠近,賦值語句=號左右加空格捏顺,函數(shù)參數(shù)之間加空格六孵,運算符優(yōu)先級高的× / ÷左右不加空格,優(yōu)先級低的+/-左右加空格幅骄。
- 水平對齊劫窒。
- 縮進表示層次。
- 空范圍拆座。
-
格式范例:
code format sample.PNG
六主巍、對象和數(shù)據(jù)結(jié)構(gòu)
-
數(shù)據(jù)抽象
隱藏實現(xiàn)關(guān)乎抽象!類并不簡單的用getter挪凑、setter將其變量推向外間孕索,
而是暴露抽象接口,以便用戶無需了解數(shù)據(jù)的實現(xiàn)就能操作數(shù)據(jù)本體躏碳。
以抽象形態(tài)表述數(shù)據(jù)搞旭。
//具象點
public class Point {
public double x;
public double y;
}
//抽象點
public interface Point {
double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
//具象機動車
public interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
//抽象機動車
public interface Vehicle {
double getPercentFuelRemaining();
}
- 數(shù)據(jù)、對象的反對稱性
對象把數(shù)據(jù)隱藏于抽象之后菇绵,暴露操作數(shù)據(jù)的函數(shù)肄渗。
數(shù)據(jù)結(jié)構(gòu)暴露其數(shù)據(jù),沒有提供有意義的函數(shù)脸甘。-
對象與數(shù)據(jù)結(jié)構(gòu)之間的二分原理:
過程式代碼(使用數(shù)據(jù)結(jié)構(gòu))便于在不改動數(shù)據(jù)結(jié)構(gòu)的前提下添加新函數(shù)恳啥,
面向?qū)ο蟠a便于在不改動既有函數(shù)的前提下添加新類。
反過來說丹诀,
過程式代碼難以添加新數(shù)據(jù)結(jié)構(gòu)钝的,因為必須修改所有函數(shù)翁垂,
面向?qū)ο蟠a難以添加新函數(shù),因為必須修改所有類硝桩。
過程式代碼.PNG
面向?qū)ο蠖鄳B(tài)代碼.PNG
-
德墨忒爾定律(迪米特法則沿猜,Law Of Demeter)
也叫做“最少了解原理”,模塊不應(yīng)該了解它所操作對象的內(nèi)部情形碗脊。
C類的函數(shù)f()只能調(diào)用以下對象的方法:
- C類的對象
- f()創(chuàng)建的對象
- 通過參數(shù)傳入的對象
- C類的實體變量對象
另一種解釋:只暴露應(yīng)該暴露的接口方法啼肩,只依賴需要依賴的對象。
System應(yīng)該只暴露close()的接口方法衙伶,而不該暴露close()內(nèi)部的細節(jié)祈坠,
Person應(yīng)該只依賴Container(硬件設(shè)備容器)的接口,而不該直接依賴System(操作系統(tǒng))矢劲。
這樣做也符合依賴倒置原則赦拘,也就是面向接口編程。
火車失事
下列代碼應(yīng)該切分成三行芬沉。
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
是否違反德墨忒爾定律躺同,取決于ctxt、options丸逸、scratchDir蹋艺、absolutePath是對象還是數(shù)據(jù)結(jié)構(gòu)。
如果是對象黄刚,應(yīng)該隱藏內(nèi)部結(jié)構(gòu)捎谨。
如果是數(shù)據(jù)結(jié)構(gòu),則需要暴露內(nèi)部結(jié)構(gòu)隘击,不算違反德墨忒爾定律侍芝。
混雜
盡量避免混合結(jié)構(gòu),一半是對象埋同,一半是數(shù)據(jù)結(jié)構(gòu),既有執(zhí)行操作的函數(shù)棵红,又有g(shù)etter/setter凶赁。同時增加了添加函數(shù)和添加數(shù)據(jù)結(jié)構(gòu)的難度。
隱藏結(jié)構(gòu)
經(jīng)查逆甜,發(fā)現(xiàn)上述代碼獲取outputDir是為了根據(jù)路徑得到BufferedOutputStream虱肄,創(chuàng)建文件,
String outFile = outputDir + "/" +className.replace('.', '/') + ".class";
FileOutputStream fout = new FileOutputStream(outFile);
BufferedOutputStream bos = new BufferedOutputStream(fout);
ctxt應(yīng)該僅僅暴露獲取BufferedOutputStream的接口方法交煞,隱藏具體實現(xiàn)咏窿。
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
-
數(shù)據(jù)傳送對象
DTO是只有公共變量(包括私有變量+公共getter/setter)、沒有函數(shù)的類素征,是最精煉的數(shù)據(jù)結(jié)構(gòu)集嵌。
Active Record是一種特殊的DTO形式萝挤,同時也會擁有save、find方法根欧,通常是對數(shù)據(jù)庫或其他數(shù)據(jù)源的之間翻譯(就是我們項目中的Domain Object怜珍,一個類對應(yīng)數(shù)據(jù)庫一張表)。Active Record往往被塞進業(yè)務(wù)規(guī)則方法凤粗,導(dǎo)致數(shù)據(jù)結(jié)構(gòu)和對象的混雜體酥泛。
應(yīng)該把Active Record當成數(shù)據(jù)結(jié)構(gòu),另外創(chuàng)建包含業(yè)務(wù)規(guī)則嫌拣、隱藏內(nèi)部數(shù)據(jù)的獨立對象柔袁。
小結(jié)
- 數(shù)據(jù)結(jié)構(gòu)暴露數(shù)據(jù),沒有明顯行為异逐。
過程式代碼操作數(shù)據(jù)結(jié)構(gòu)瘦馍,添加新的函數(shù)無需修改數(shù)據(jù)結(jié)構(gòu),但添加新的數(shù)據(jù)結(jié)構(gòu)需要修改所有函數(shù)应役。 - 對象暴露行為情组,隱藏數(shù)據(jù)。
面向?qū)ο笫酱a操作對象箩祥,添加新的類無需修改既有函數(shù)院崇,但添加新的函數(shù)需要修改所有類。
不應(yīng)對任何一種抱有成見袍祖,根據(jù)具體情況使用底瓣。
七、錯誤處理
對錯誤的處理很有必要蕉陋,也很重要捐凭,要保證出現(xiàn)錯誤時程序仍能正常運行。
但不能因此讓代碼邏輯變得混亂凳鬓。
使用異常而非返回碼
使用異常進行錯誤處理茁肠,能把實現(xiàn)部分和錯誤處理分離,以免錯誤處理影響實現(xiàn)部分的邏輯缩举。先寫Try-Catch-Finally
使用不可控異常
我的理解:可控異常違反開閉原則垦梆,修改內(nèi)層方法拋出一個可控異常,外層方法都必須修改捕獲這個異常仅孩,導(dǎo)致從內(nèi)到外的修改鏈托猩。
但是使用java編寫文件處理、反射的程序時辽慕,不可避免的需要捕獲可控異常京腥。
自定義的異常都應(yīng)該繼承RuntimeException(不可控異常)。給出異常發(fā)生的環(huán)境說明
-
依調(diào)用者需要定義異常類
定義異常溅蛉,要考慮它們?nèi)绾伪徊东@公浪。
對于第三方API拋出各種不同異常的情況他宛,可以打包API拋出通用的異常類型,簡化調(diào)用時的代碼因悲。
直接在調(diào)用API的地方捕獲異常:
api exception1.PNG
打包調(diào)用API堕汞,簡化調(diào)用代碼:
api exception2.PNG 定義常規(guī)流程
采取特例模式(SPECIAL CASE PATTERN),創(chuàng)建一個類或配置一個對象晃琳,用來處理特例讯检。客戶代碼就不用應(yīng)付異常行為了卫旱。不要返回或傳遞null值
方法返回null人灼,不如拋出異常或返回特例對象顾翼,否則會有NullPointerException的隱患投放。
小結(jié)
將錯誤處理和主要邏輯隔離,就能寫出整潔而強壯的代碼适贸。
八灸芳、邊界
我們不可避免的需要使用第三方或者其他團隊開發(fā)的組件,整合到我們自己的代碼中拜姿,這章主要講如何保持軟件邊界整潔烙样。
- 使用第三方代碼
- Map的接口功能非常豐富,接收者不要刪除其中的映射
- Map的接口一旦修改蕊肥,許多地方代碼需要修改
- 不要把Map(或其他在邊界上的接口)在系統(tǒng)中傳遞谒获,否則也要保留在類中,避免從公共API返回邊界接口壁却,或把邊界接口作為參數(shù)傳遞給公共API批狱。
通過編寫學習型測試來理解第三方代碼
-
使用尚不存在的代碼
使用尚不存在的代碼.PNG
通信控制器依賴于Transmitter API,但API尚未定義且不受我們控制展东。
先定義適合通信控制器使用的接口Transmitter赔硫,一旦提供了Transmitter API,就編寫Transmitter Adapter來跨接琅锻。適配器封裝了與API的互動卦停,并且如果API發(fā)生變動,只需要修改適配器恼蓬。
小結(jié)
邊界上會發(fā)生我們不可控的改動,要避免我們的代碼過多依賴第三方代碼的細節(jié)僵芹。
使用Sensor類封裝第三方接口的返回結(jié)果处硬,或使用Adapter模式將第三方接口轉(zhuǎn)換為我們需要的接口。
使用Adapter模式不僅能將不兼容的接口改寫成兼容的接口拇派,還能對第三方接口重新封裝來避免邊界變化對系統(tǒng)的影響荷辕。
九凿跳、單元測試
- TDD三定律
- 在編寫不能通過的單元測試前,不能編寫生產(chǎn)代碼
- 只能編寫剛好不能通過的單元測試疮方,不能編譯也算不通過
-
只能編寫剛好足以通過當前失敗測試的生產(chǎn)代碼
我對上述定律的理解控嗜,首先必須先寫單元測試再寫實現(xiàn),同時在寫單元測試和實現(xiàn)時必須保持小步前進骡显。由于真實項目的業(yè)務(wù)邏輯往往很復(fù)雜疆栏,一個story如何拆分tasking,需要在小步和項目進度之間做權(quán)衡惫谤,也取決于對TDD和重構(gòu)掌握的熟練程度壁顶。
整潔的測試
測試代碼最重要的是可讀性,明確溜歪、簡潔若专、有足夠的表達力。一個測試一個斷言
作者認為單個斷言是個好的準則蝴猪,一個測試方法的斷言數(shù)量要盡量少调衰。
但太過強調(diào)單個斷言,會導(dǎo)致given和when部分有很多重復(fù)代碼自阱。
我自己TDD的體會咱士,一個測試方法對應(yīng)一個test-case,如果測試用例拆得足夠小胳赌,測試方法中的斷言自然就會少酥诽,這和作者提到的每個測試一個概念應(yīng)該是一致的。F.I.R.S.T
測試還應(yīng)遵守以下5條規(guī)則琼懊。
- 快速(fast) 測試應(yīng)該能快速運行阁簸,太慢了你就不會頻繁的運行,就不會盡早發(fā)現(xiàn)問題哼丈。
- 獨立(independent) 測試應(yīng)該相互獨立启妹,某個測試不應(yīng)該為下個測試設(shè)定條件。當測試相互依賴醉旦,一個沒通過導(dǎo)致一連串的測試失敗饶米,使問題診斷變的困難。
- 可重復(fù)(repeatable) 測試應(yīng)該可以在任何環(huán)境中重復(fù)通過车胡。
- 自足驗證(self-validating) 測試應(yīng)該有布爾值輸出檬输,無論通過或失敗,不應(yīng)該是查看日志文件去確認
- 及時(timely) 單元測試應(yīng)該恰好在使其通過的生產(chǎn)代碼之前編寫匈棘。
小結(jié)
關(guān)于單元測試的內(nèi)容還有很多丧慈,這一章主要還是強調(diào)保持整潔的測試。
十、類
類的組織
公共靜態(tài)常量 - 私有靜態(tài)變量 - 私有實體變量 - 公共方法 - 私有方法逃默,保證自頂向下的閱讀順序鹃愤。類應(yīng)該短小
如何判斷一個類是否太長,主要看類是否承擔了多個職責完域。
單一職責原則是OO最容易理解和遵循的原則软吐,通常也是被違反得最多的原則。類或模塊應(yīng)有且只有一條加以修改的理由吟税。系統(tǒng)應(yīng)該有許多短小的類而不是巨大的類組成凹耙,每個小類封裝一個職責。內(nèi)聚
如果一個類中的每個變量都被每個方法所使用乌妙,則該類具有最大的內(nèi)聚性使兔。內(nèi)聚性高,意味著類中的方法和變量相互依賴藤韵,相互結(jié)合成一個邏輯整體虐沥。
保持內(nèi)聚性就能得到短小的類,一旦發(fā)現(xiàn)類失去內(nèi)聚性泽艘,就拆分它欲险!當某些實體變量只被少數(shù)方法使用,就應(yīng)該拆分出一個類匹涮。為了修改而組織
通過多態(tài)將一個大類中的細節(jié)隔離天试,等同于把修改隔離,符合開閉原則然低。
讓調(diào)用方依賴接口而不依賴細節(jié)喜每,符合依賴倒置原則。
隔離細節(jié)雳攘,更利于單元測試带兜。
十一、系統(tǒng)
將系統(tǒng)的構(gòu)造和使用分開:構(gòu)造和使用是不一樣的過程吨灭。
工廠
使用抽象工廠模式刚照,將構(gòu)造的細節(jié)隔離于應(yīng)用程序之外。依賴注入(DI/IOC)
在依賴管理情景中喧兄,對象不應(yīng)該負責實例化對自身的依賴无畔,反之,它應(yīng)該將這份權(quán)責移交給其他有權(quán)利的機制吠冤,從而實現(xiàn)控制的反轉(zhuǎn)浑彰。擴容
“一開始就做對的系統(tǒng)”純屬神話。
反之拯辙,我們應(yīng)該只實現(xiàn)今天的用戶的需求闸昨。
然后重構(gòu),明天再擴容系統(tǒng)薄风,實現(xiàn)新用戶的需求饵较。面向切面編程(AOP)
AOP中,被稱為方面(aspect)的模塊構(gòu)造指明了系統(tǒng)中哪些點的行為會以某種一致的方式被修改遭赂,從而支持某種特定的場景循诉。這種說明是用某種簡潔的聲明(Attribute)或編程機制來實現(xiàn)的。
小結(jié)
這一章的概念和描述比較多撇他,例子不多茄猫,看完并沒有很深的體會。
但是工廠模式困肩、依賴注入划纽、AOP這些在項目中都有應(yīng)用,關(guān)于Spring AOP可以參考《Spring實戰(zhàn)》和這篇文章Spring之AOP由淺入深
十二锌畸、迭進
簡單設(shè)計規(guī)則1 運行所有測試
緊耦合的代碼難以編寫測試勇劣。同樣編寫測試越多,就會越遵循DIP之類的原則潭枣,使用依賴注入比默,接口和抽象等工具盡可能減少耦合。如此一來設(shè)計就會有長足進步盆犁。遵循有關(guān)編寫測試并持續(xù)運行測試的命咐、明確的規(guī)則,系統(tǒng)就會更貼近OO低耦合度谐岁、高內(nèi)聚的目標醋奠。簡單設(shè)計規(guī)則2 重構(gòu)
在重構(gòu)過程中,可以應(yīng)用有關(guān)優(yōu)秀軟件設(shè)計的一切知識伊佃,提升內(nèi)聚性窜司,降低耦合度。換句話說:消除重復(fù)锭魔,保證表達力例证,盡可能的減少類和方法的數(shù)量。不可重復(fù)
重復(fù)代表著額外的工作迷捧、額外的風險和額外不必要的復(fù)雜度织咧。重復(fù)有多種表現(xiàn)。雷同的代碼行是一種漠秋。不但是從代碼行的角度笙蒙,也要從功能上消除重復(fù)。揭示程序員意圖
十三庆锦、并發(fā)編程
為什么要并發(fā)
并發(fā)是一種解耦策略捅位,它幫助我們把做什么(目的)和何時(時機)做分解開。
在單線程應(yīng)用中,目的與時機緊密耦合艇搀。
而解耦目的與時機能明顯地改進應(yīng)用程序的吞吐量和結(jié)構(gòu)尿扯。
從結(jié)構(gòu)的角度看,應(yīng)用程序看起來更像是許多臺協(xié)同工作的計算機焰雕,而不是一個大循環(huán)衷笋。
單線程程序許多時間花在等待Web套接字I/O結(jié)束上面。迷思與誤解
并發(fā)總能改進性能:并發(fā)有時能改進性能矩屁,但只在多個線程或處理器之間能分享大量等待時間的時候管用辟宗。
并發(fā)編程無需修改設(shè)計:并發(fā)算法的設(shè)計可能與單線程系統(tǒng)的設(shè)計極不相同,目的與時機的解耦往往對系統(tǒng)結(jié)構(gòu)產(chǎn)生巨大影響吝秕。
在采用Web和EJB容器時泊脐,理解并發(fā)問題不重要:最好了解容器在做什么,如何應(yīng)付并發(fā)更新烁峭、死鎖等問題容客。
并發(fā)會在性能和編寫額外代碼上增加一些開銷。
正確的并發(fā)是復(fù)雜的则剃,即使對于簡單的問題也是如此耘柱。
并發(fā)缺陷并非總能重現(xiàn),所以常被看做偶發(fā)事件而忽略棍现,而未被當做真的缺陷看待调煎。
并發(fā)常常需要對設(shè)計策略的根本性修改。
平時工作中并發(fā)編程涉及得很少己肮,讀起來體會不深士袄,轉(zhuǎn)載一篇java并發(fā)編程相關(guān)的文章,以后繼續(xù)學習
關(guān)于Java并發(fā)編程的總結(jié)和思考