阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

很多人都知道,阿里巴巴在2017發(fā)布了《阿里巴巴Java開(kāi)發(fā)手冊(cè)》,前后推出了很多個(gè)版本,并在后續(xù)推出了與之配套的IDEA插件和書(shū)籍。

創(chuàng)新互聯(lián)建站一直秉承“誠(chéng)信做人,踏實(shí)做事”的原則,不欺瞞客戶(hù),是我們最起碼的底線! 以服務(wù)為基礎(chǔ),以質(zhì)量求生存,以技術(shù)求發(fā)展,成交一個(gè)客戶(hù)多一個(gè)朋友!為您提供網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、成都網(wǎng)頁(yè)設(shè)計(jì)、微信平臺(tái)小程序開(kāi)發(fā)、成都網(wǎng)站開(kāi)發(fā)、成都網(wǎng)站制作、成都軟件開(kāi)發(fā)、APP應(yīng)用開(kāi)發(fā)是成都本地專(zhuān)業(yè)的網(wǎng)站建設(shè)和網(wǎng)站設(shè)計(jì)公司,等你一起來(lái)見(jiàn)證!

相信很多Java開(kāi)發(fā)都或多或少看過(guò)這份手冊(cè),這份手冊(cè)有7個(gè)章節(jié),覆蓋了編程規(guī)約、異常日志、單元測(cè)試、安全規(guī)約、MySQL數(shù)據(jù)庫(kù)、工程結(jié)構(gòu)以及設(shè)計(jì)規(guī)約等方面。

這份規(guī)約可以說(shuō)是覆蓋了Java開(kāi)發(fā)的方方面面,如果還有人沒(méi)看的話,強(qiáng)烈建議大家好好看看,并且仔細(xì)研讀。

手冊(cè)中,有那么一些規(guī)則,是比較容易理解的。比如一些變量命名規(guī)范,有另外一些規(guī)則,是不太容易理解的,背后是有很多思考的,有一些則是阿里這么多年來(lái)遇到的坑的總結(jié)。

這份手冊(cè)在誕生之初,是在阿里內(nèi)部的,那時(shí)候就引起了廣泛的討論。最終外界看到的那份手冊(cè),是阿里無(wú)數(shù)工程師"挑剔"后的結(jié)果,可以說(shuō)是凝聚了無(wú)數(shù)工程師成功的經(jīng)驗(yàn)、踩過(guò)的坑等。

其實(shí),規(guī)約最大的價(jià)值,應(yīng)該是促使人去思考規(guī)約制定背后的思考。真的去探查規(guī)約背后的原理,這個(gè)過(guò)程中可以學(xué)習(xí)到很多東西。

《阿里巴巴Java開(kāi)發(fā)手冊(cè)》還沒(méi)有的小伙伴可以來(lái)私信我【阿里學(xué)習(xí)手冊(cè)】領(lǐng)取一份

一、為什么阿里巴巴禁止工程師直接使用日志系統(tǒng)(Log4j、Logback)中的 API

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

在Java生態(tài)體系中,圍繞著日志,有很多成熟的解決方案。關(guān)于日志輸出,主要有兩類(lèi)工具。

一類(lèi)是日志框架,主要用來(lái)進(jìn)行日志的輸出的,比如輸出到哪個(gè)文件,日志格式如何等。另外一類(lèi)是日志門(mén)面,主要一套通用的API,用來(lái)屏蔽各個(gè)日志框架之間的差異的。

所以,對(duì)于Java工程師來(lái)說(shuō),關(guān)于日志工具的使用,最佳實(shí)踐就是在應(yīng)用中使用如Log4j + SLF4J 這樣的組合來(lái)進(jìn)行日志輸出。

這樣做的最大好處,就是業(yè)務(wù)層的開(kāi)發(fā)不需要關(guān)心底層日志框架的實(shí)現(xiàn)及細(xì)節(jié),在編碼的時(shí)候也不需要考慮日后更換框架所帶來(lái)的成本。這也是門(mén)面模式所帶來(lái)的好處。

二、為什么阿里巴巴建議集合初始化時(shí),指定集合容量大???

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

HashMap有擴(kuò)容機(jī)制,就是當(dāng)達(dá)到擴(kuò)容條件時(shí)會(huì)進(jìn)行擴(kuò)容。如果我們沒(méi)有設(shè)置初始容量大小,隨著元素的不斷增加,HashMap會(huì)發(fā)生多次擴(kuò)容,而HashMap中的擴(kuò)容機(jī)制決定了每次擴(kuò)容都需要重建hash表,是非常影響性能的。

默認(rèn)情況下,當(dāng)我們?cè)O(shè)置HashMap的初始化容量時(shí),實(shí)際上HashMap會(huì)采用第一個(gè)大于該數(shù)值的2的冪作為初始化容量。

但是,為了最大程度的避免擴(kuò)容帶來(lái)的性能消耗,我們建議可以把默認(rèn)容量的數(shù)字設(shè)置成expectedSize / 0.75F + 1.0F 。在日常開(kāi)發(fā)中,可以使用

Map<String,String>map=Maps.newHashMapWithExpectedSize(10);

來(lái)創(chuàng)建一個(gè)HashMap,計(jì)算的過(guò)程guava會(huì)幫我們完成。

但是,以上的操作是一種用內(nèi)存換性能的做法,真正使用的時(shí)候,要考慮到內(nèi)存的影響。

三、為什么阿里巴巴禁止在 foreach 循環(huán)里進(jìn)行元素的 remove/add 操作

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

我們使用的增強(qiáng)for循環(huán),其實(shí)是Java提供的語(yǔ)法糖,其實(shí)現(xiàn)原理是借助Iterator進(jìn)行元素的遍歷。

但是如果在遍歷過(guò)程中,不通過(guò)Iterator,而是通過(guò)集合類(lèi)自身的方法對(duì)集合進(jìn)行添加/刪除操作。那么在Iterator進(jìn)行下一次的遍歷時(shí),經(jīng)檢測(cè)發(fā)現(xiàn)有一次集合的修改操作并未通過(guò)自身進(jìn)行,那么可能是發(fā)生了并發(fā)被其他線程執(zhí)行的,這時(shí)候就會(huì)拋出異常,來(lái)提示用戶(hù)可能發(fā)生了并發(fā)修改,這就是所謂的fail-fast機(jī)制。

當(dāng)然還是有很多種方法可以解決這類(lèi)問(wèn)題的。比如使用普通for循環(huán)、使用Iterator進(jìn)行元素刪除、使用Stream的filter、使用fail-safe的類(lèi)等。

四、為什么阿里巴巴禁止把SimpleDateFormat定義為static類(lèi)型的?

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

SimpleDateFormat主要可以在String和Date之間做轉(zhuǎn)換,還可以將時(shí)間轉(zhuǎn)換成不同時(shí)區(qū)輸出。但是在并發(fā)場(chǎng)景中SimpleDateFormat是不能保證線程安全的,需要開(kāi)發(fā)者自己來(lái)保證其安全性。

SimpleDateFormat中的format方法在執(zhí)行過(guò)程中,會(huì)使用一個(gè)成員變量calendar來(lái)保存時(shí)間。這其實(shí)就是問(wèn)題的關(guān)鍵。

如果一個(gè)SimpleDateFormat使用的是static定義的。那么這個(gè)SimpleDateFormat就是一個(gè)共享變量,隨之,SimpleDateFormat中的calendar也就可以被多個(gè)線程訪問(wèn)到。就會(huì)有并發(fā)安全問(wèn)題。

五、為什么阿里巴巴不建議在for循環(huán)中使用"+"進(jìn)行字符串拼接

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

使用+拼接字符串,其實(shí)只是Java提供的一個(gè)語(yǔ)法糖,通過(guò)反編譯,我們可以發(fā)現(xiàn),其實(shí)字符串常量使用"+"在拼接過(guò)程中,是將String轉(zhuǎn)成了StringBuilder后,使用其append方法進(jìn)行處理的。

如果在一個(gè)for循環(huán)中,使用"+"對(duì)字符串進(jìn)行拼接,那么每一次都會(huì)重新new一個(gè)StringBuilder,然后再把String轉(zhuǎn)成StringBuilder,再進(jìn)行append。

而頻繁的新建對(duì)象當(dāng)然要耗費(fèi)很多時(shí)間了,不僅僅會(huì)耗費(fèi)時(shí)間,頻繁的創(chuàng)建對(duì)象,還會(huì)造成內(nèi)存資源的浪費(fèi)。

六、為什么阿里巴巴要求程序員謹(jǐn)慎修改serialVersionUID 字段的值

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

序列化提供了一種方案,可以讓你在即使JVM停機(jī)的情況下也能把對(duì)象保存下來(lái)的方案。就像我們平時(shí)用的U盤(pán)一樣。把Java對(duì)象序列化成可存儲(chǔ)或傳輸?shù)男问剑ㄈ缍M(jìn)制流),比如保存在文件中。這樣,當(dāng)再次需要這個(gè)對(duì)象的時(shí)候,從文件中讀取出二進(jìn)制流,再?gòu)亩M(jìn)制流中反序列化出對(duì)象。

虛擬機(jī)是否允許反序列化,不僅取決于類(lèi)路徑和功能代碼是否一致,一個(gè)非常重要的一點(diǎn)是兩個(gè)類(lèi)的序列化 ID 是否一致,這個(gè)所謂的序列化ID,就是我們?cè)诖a中定義的serialVersionUID。

在進(jìn)行反序列化時(shí),JVM會(huì)把傳來(lái)的字節(jié)流中的serialVersionUID與本地相應(yīng)實(shí)體類(lèi)的serialVersionUID進(jìn)行比較,如果相同就認(rèn)為是一致的,可以進(jìn)行反序列化,否則就會(huì)出現(xiàn)序列化版本不一致的異常,即是InvalidCastException。

七、為什么阿里巴巴要求謹(jǐn)慎使用ArrayList中的subList方法

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

subList是List接口中定義的一個(gè)方法,該方法主要用于返回一個(gè)集合中的一段、可以理解為截取一個(gè)集合中的部分元素,他的返回值也是一個(gè)List。

但是subList 返回的并不是一個(gè)全新的List,而是一個(gè)視圖。就是說(shuō),SubList并沒(méi)有重新創(chuàng)建一個(gè)List,而是直接引用了原有的List(返回了父類(lèi)的視圖),只是指定了一下他要使用的元素的范圍而已(從fromIndex(包含),到toIndex(不包含))。

所以,首先我們無(wú)法將subList方法得到的集合直接轉(zhuǎn)換成ArrayList。因?yàn)镾ubList只是ArrayList的內(nèi)部類(lèi),他們之間并沒(méi)有繼承關(guān)系,故無(wú)法直接進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換。

另外,視圖和原List的修改還需要注意幾點(diǎn),尤其是他們之間的相互影響:

  • 1、對(duì)父(sourceList)子(subList)List做的非結(jié)構(gòu)性修改(non-structural changes),都會(huì)影響到彼此。

  • 2、對(duì)子List做結(jié)構(gòu)性修改,操作同樣會(huì)反映到父List上。

  • 3、對(duì)父List做結(jié)構(gòu)性修改,會(huì)拋出異常ConcurrentModificationException。

所以,阿里巴巴Java開(kāi)發(fā)手冊(cè)中有另外一條規(guī)定:

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

八、為什么阿里巴巴建議開(kāi)發(fā)者謹(jǐn)慎使用繼承?

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知


作為一門(mén)面向?qū)ο箝_(kāi)發(fā)的語(yǔ)言,代碼復(fù)用是Java引人注意的功能之一。Java代碼的復(fù)用有繼承,組合以及代理三種具體的表現(xiàn)形式。

繼承,在寫(xiě)代碼的時(shí)候就要指明具體繼承哪個(gè)類(lèi),所以,類(lèi)的繼承關(guān)系是在編譯期就確定的。并且從基類(lèi)繼承來(lái)的實(shí)現(xiàn)是無(wú)法在運(yùn)行期動(dòng)態(tài)改變的,因此降低了應(yīng)用的靈活性。

組合,在寫(xiě)代碼的時(shí)候可以采用面向接口編程。所以,類(lèi)的組合關(guān)系一般在運(yùn)行期確定。另外,代碼復(fù)用方式上也有一定區(qū)別:

  • 繼承結(jié)構(gòu)中,父類(lèi)的內(nèi)部細(xì)節(jié)對(duì)于子類(lèi)是可見(jiàn)的。所以我們通常也可以說(shuō)通過(guò)繼承的代碼復(fù)用是一種白盒式代碼復(fù)用。如果基類(lèi)的實(shí)現(xiàn)發(fā)生改變,那么派生類(lèi)的實(shí)現(xiàn)也將隨之改變。這樣就導(dǎo)致了子類(lèi)行為的不可預(yù)知性。

  • 組合是通過(guò)對(duì)現(xiàn)有的對(duì)象進(jìn)行拼裝(組合)產(chǎn)生新的、更復(fù)雜的功能。因?yàn)樵趯?duì)象之間,各自的內(nèi)部細(xì)節(jié)是不可見(jiàn)的,所以我們也說(shuō)通過(guò)組合的代碼復(fù)用是黑盒式代碼復(fù)用。因?yàn)榻M合中一般都定義一個(gè)類(lèi)型,所以在編譯期根本不知道具體會(huì)調(diào)用哪個(gè)實(shí)現(xiàn)類(lèi)的方法。

還有,Java中不支持多繼承,而組合是沒(méi)有限制的。就像一個(gè)人只能有一個(gè)父親,但是他可以有很很多輛車(chē)。

九、為什么阿里巴巴禁止開(kāi)發(fā)人員使用isSuccess作為變量名

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

?fastjson和jackson在把對(duì)象序列化成json字符串的時(shí)候,是通過(guò)反射遍歷出該類(lèi)中的所有g(shù)etter方法,得到getHollis和isSuccess,然后根據(jù)JavaBeans規(guī)則,他會(huì)認(rèn)為這是兩個(gè)屬性hollis和success的值。

但是Gson并不是這么做的,他是通過(guò)反射遍歷該類(lèi)中的所有屬性,并把其值序列化成json

可以看到,由于不同的序列化工具,在進(jìn)行序列化的時(shí)候使用到的策略是不一樣的,所以,對(duì)于同一個(gè)類(lèi)的同一個(gè)對(duì)象的序列化結(jié)果可能是不同的。

如果對(duì)于同一個(gè)對(duì)象,我使用fastjson進(jìn)行序列化,再使用Gson反序列化,并且恰巧這個(gè)對(duì)象中某個(gè)屬性是以isXXX命名的,那么就會(huì)產(chǎn)生問(wèn)題。

作為開(kāi)發(fā)者,我們應(yīng)該想辦法盡量避免這種問(wèn)題的發(fā)生,對(duì)于POJO的設(shè)計(jì)者來(lái)說(shuō),只需要做簡(jiǎn)單的一件事就可以解決這個(gè)問(wèn)題了,那就是把isSuccess改為success。

十、為什么阿里巴巴不讓使用 COUNT(列名)或 COUNT(常量)來(lái)替代 COUNT(*)呢

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

因?yàn)镃OUNT(*)是SQL92定義的標(biāo)準(zhǔn)統(tǒng)計(jì)行數(shù)的語(yǔ)法,所以MySQL對(duì)他進(jìn)行了很多優(yōu)化,MyISAM中會(huì)直接把表的總行數(shù)單獨(dú)記錄下來(lái)供COUNT(*)查詢(xún),而InnoDB則會(huì)在掃表的時(shí)候選擇最小的索引來(lái)降低成本。當(dāng)然,這些優(yōu)化的前提都是沒(méi)有進(jìn)行where和group的條件查詢(xún)。

在InnoDB中COUNT(*)和COUNT(1)實(shí)現(xiàn)上沒(méi)有區(qū)別,而且效率一樣,但是COUNT(字段)需要進(jìn)行字段的非NULL判斷,所以效率會(huì)低一些。

因?yàn)镃OUNT(*)是SQL92定義的標(biāo)準(zhǔn)統(tǒng)計(jì)行數(shù)的語(yǔ)法,并且效率高,所以請(qǐng)直接使用COUNT(*)查詢(xún)表的行數(shù)!

十一、為什么阿里巴巴不允許使用Executors創(chuàng)建線程池?

阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知

Java中的BlockingQueue主要有兩種實(shí)現(xiàn),分別是ArrayBlockingQueue 和 LinkedBlockingQueue。

ArrayBlockingQueue是一個(gè)用數(shù)組實(shí)現(xiàn)的有界阻塞隊(duì)列,必須設(shè)置容量。

LinkedBlockingQueue是一個(gè)用鏈表實(shí)現(xiàn)的有界阻塞隊(duì)列,容量可以選擇進(jìn)行設(shè)置,不設(shè)置的話,將是一個(gè)無(wú)邊界的阻塞隊(duì)列,最大長(zhǎng)度為Integer.MAX_VALUE。

這里的問(wèn)題就出在:不設(shè)置的話,將是一個(gè)無(wú)邊界的阻塞隊(duì)列,最大長(zhǎng)度為Integer.MAX_VALUE。也就是說(shuō),如果我們不設(shè)置LinkedBlockingQueue的容量的話,其默認(rèn)容量將會(huì)是Integer.MAX_VALUE。

而newFixedThreadPool中創(chuàng)建LinkedBlockingQueue時(shí),并未指定容量。此時(shí),LinkedBlockingQueue就是一個(gè)無(wú)邊界隊(duì)列,對(duì)于一個(gè)無(wú)邊界隊(duì)列來(lái)說(shuō),是可以不斷的向隊(duì)列中加入任務(wù)的,這種情況下就有可能因?yàn)槿蝿?wù)過(guò)多而導(dǎo)致內(nèi)存溢出問(wèn)題。

上面提到的問(wèn)題主要體現(xiàn)在newFixedThreadPool和newSingleThreadExecutor兩個(gè)工廠方法上,并不是說(shuō)newCachedThreadPool和newScheduledThreadPool這兩個(gè)方法就安全了,這兩種方式創(chuàng)建的最大線程數(shù)可能是Integer.MAX_VALUE,而創(chuàng)建這么多線程,必然就有可能導(dǎo)致OOM。

總結(jié)

以上,就是我之前一段時(shí)間通過(guò)學(xué)習(xí)《手冊(cè)》中的部分規(guī)則之后,自己總結(jié)的一些內(nèi)容,這個(gè)過(guò)程中自己也學(xué)習(xí)到很多東西。

所以想說(shuō),這才是學(xué)習(xí)《手冊(cè)》的正確姿勢(shì),這樣才能最大程度的成長(zhǎng)!

這個(gè)系列還在繼續(xù)更新,后面還會(huì)會(huì)逐步完善。歡迎關(guān)注與交流。

《阿里巴巴Java開(kāi)發(fā)手冊(cè)》還沒(méi)有的小伙伴可以來(lái)加VX:haolagui521備注“51CTO”領(lǐng)取一份

分享名稱(chēng):阿里巴巴Java開(kāi)發(fā)手冊(cè)正確學(xué)習(xí)姿勢(shì)是怎樣的?刷新代碼規(guī)范認(rèn)知
文章網(wǎng)址:http://muchs.cn/article16/ijoogg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、網(wǎng)站維護(hù)網(wǎng)站收錄、品牌網(wǎng)站設(shè)計(jì)網(wǎng)頁(yè)設(shè)計(jì)公司、App設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷(xiāo)型網(wǎng)站建設(shè)