一、前言
本文參考《阿里巴巴Java開發(fā)手冊》,這本書主要定義了一些代碼的規(guī)范以及一些注意事項。我只根據(jù)我自己的不足,摘錄了一些內(nèi)容,方便以后查閱。

二、讀書筆記
命名
1、代碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。
2、常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長。
3、抽象類命名使用 Abstract 或 Base 開頭; 異常類命名使用 Exception 結尾; 測試類命名以它要測試的類的名稱開始,以 Test 結尾。
4、中括號是數(shù)組類型的一部分,數(shù)組定義如下: String[] args;
5、POJO 類中布爾類型的變量,都不要加 is,否則部分框架解析會引起序列化錯誤。
反例: 定義為基本數(shù)據(jù)類型 Boolean isDeleted; 的屬性,它的方法也是 isDeleted()。 RPC框架在反向解析的時候, “以為”對應的屬性名稱是 deleted,導致屬性獲取不到,進而拋出異常。
6、包名統(tǒng)一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統(tǒng)一使用單數(shù)形式,但是類名如果有復數(shù)含義,類名可以使用復數(shù)形式。
7、如果使用到了設計模式,建議在類名中體現(xiàn)出具體模式。有利于閱讀者快速理解架構設計思想。
8、接口類中的方法和屬性不要加任何修飾符號(public 也不要加) ,保持代碼的簡潔性,并加上有效的 Javadoc 注釋。盡量不要在接口里定義變量,如果一定要定義變量,肯定是與接口方法相關,并且是整個應用的基礎常量。
9、枚舉類名建議帶上 Enum 后綴,枚舉成員名稱需要全大寫,單詞間用下劃線隔開。
說明: 枚舉其實就是特殊的常量類,且構造方法默認強制為私有。
正例: 枚舉名字: DealStatusEnum, 成員名稱: SUCCESS / UNKOWN_REASON。
10、各層命名規(guī)約:A) Service/DAO 層方法命名規(guī)約
1) 獲取單個對象的方法用 get 做前綴。
2) 獲取多個對象的方法用 list 做前綴。
3) 獲取統(tǒng)計值的方法用 count 做前綴。
4) 插入的方法用 save(推薦) 或 insert 做前綴。
5) 刪除的方法用 remove(推薦) 或 delete 做前綴。
6) 修改的方法用 update 做前綴。
B) 領域模型命名規(guī)約
1) 數(shù)據(jù)對象: xxxDO, xxx 即為數(shù)據(jù)表名。
2) 數(shù)據(jù)傳輸對象: xxxDTO, xxx 為業(yè)務領域相關的名稱。
3) 展示對象: xxxVO, xxx 一般為網(wǎng)頁名稱。
4) POJO 是 DO/DTO/BO/VO 的統(tǒng)稱,禁止命名成 xxxPOJO。
常量定義
1、不允許任何未經(jīng)定義的常量直接出現(xiàn)在代碼中。反例: String key = "Id#taobao_" + tradeId;cache.put(key, value);
2、long 或者 Long 初始賦值時,必須使用大寫的 L,不能是小寫的 l,小寫容易跟數(shù)字1 混淆,造成誤解。
3、不要使用一個常量類維護所有常量,應該按常量功能進行歸類,分開維護。
如:緩存相關的常量放在類: CacheConsts 下; 系統(tǒng)配置相關的常量放在類: ConfigConsts 下。
OOP規(guī)約
1、避免通過一個類的對象引用訪問此類的靜態(tài)變量或靜態(tài)方法,無謂增加編譯器解析成本,直接用類名來訪問即可。
2、外部正在調(diào)用或者二方庫依賴的接口,不允許修改方法簽名,避免對接口調(diào)用方產(chǎn)生影響。接口過時必須加@Deprecated 注解,并清晰地說明采用的新接口或者新服務是什么。
3、不能使用過時的類或方法。
4、Object 的 equals 方法容易拋空指針異常,應使用常量或確定有值的對象來調(diào)用equals
正例: "test".equals(object);
反例: object.equals("test");
5、所有的相同類型的包裝類對象之間值的比較,全部使用 equals 方法比較。對于 Integer var = ? 在-128 至 127 范圍內(nèi)的賦值, Integer 對象是在IntegerCache.cache 產(chǎn)生,會復用已有對象,這個區(qū)間內(nèi)的 Integer 值可以直接使用==進行判斷,但是這個區(qū)間之外的所有數(shù)據(jù),都會在堆上產(chǎn)生,并不會復用已有對象,這是一個大坑,推薦使用 equals 方法進行判斷。
6、關于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標準如下
:1) 【強制】 所有的 POJO 類屬性必須使用包裝數(shù)據(jù)類
2) 【強制】 RPC 方法的返回值和參數(shù)必須使用包裝數(shù)
3) 【推薦】 所有的局部變量使用基本數(shù)據(jù)類型。說明:用基本數(shù)據(jù)類型數(shù)據(jù)默認值是0,而包裝數(shù)據(jù)類型默認值是null,數(shù)據(jù)庫的查詢結果可能為null,因為自動拆箱,用基本數(shù)據(jù)類型接收有NPE風險。
7、定義 DO/DTO/VO 等 POJO 類時,不要設定任何屬性默認值(在數(shù)據(jù)提取時并沒有置入具體值,在更新其它字段時又附帶更新了此字段,導致創(chuàng)建時間被修改成當前時間。)
8、序列化類新增屬性時,請不要修改 serialVersionUID 字段,避免反序列失敗; 如果完全不兼容升級,避免反序列化混亂,那么請修改 serialVersionUID 值。注意 serialVersionUID 不一致會拋出序列化運行時異常。
9、構造方法里面禁止加入任何業(yè)務邏輯,如果有初始化邏輯,請放在 init 方法中。
10、類內(nèi)方法定義順序依次是:公有方法或保護方法 > 私有方法 > getter/setter方法。
11、循環(huán)體內(nèi),字符串的連接方式,使用 StringBuilder 的 append 方法進行擴展。
12、慎用 Object 的 clone 方法來拷貝對象。對象的 clone 方法默認是淺拷貝,若想實現(xiàn)深拷貝需要重寫 clone 方法實現(xiàn)屬性對象的拷貝。
13、工具類不允許有 public 或 default 構造方法。
集合處理
1、ArrayList的subList結果不可強轉成ArrayList,否則會拋出 ClassCastException異常: java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。subList 返回的是 ArrayList 的內(nèi)部類 SubList,并不是 ArrayList ,而是ArrayList 的一個視圖,對于 SubList 子列表的所有操作最終會反映到原列表上。
2、在 subList 場景中, 高度注意對原集合元素個數(shù)的修改,會導致子列表的遍歷、增加、刪除均產(chǎn)生 ConcurrentModificationException 異常。
3、使用集合轉數(shù)組的方法,必須使用集合的 toArray(T[] array),傳入的是類型完全一樣的數(shù)組,大小就是 list.size()。
說明: 使用 toArray 帶參方法,入?yún)⒎峙涞臄?shù)組空間不夠大時, toArray 方法內(nèi)部將重新分配內(nèi)存空間,并返回新數(shù)組地址; 如果數(shù)組元素大于實際所需,下標為[ list.size() ]的數(shù)組元素將被置為 null,其它數(shù)組元素保持原值,因此最好將方法入?yún)?shù)組大小定義與集合元素個數(shù)一致。
正例:
Listlist = new ArrayList(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);
反例: 直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[]類,若強轉其它類型數(shù)組將出現(xiàn) ClassCastException 錯誤
4、使用工具類 Arrays.asList()把數(shù)組轉換成集合時,不能使用其修改集合相關的方法,它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。
說明: asList 的返回對象是一個 Arrays 內(nèi)部類,并沒有實現(xiàn)集合的修改方法。Arrays.asList體現(xiàn)的是適配器模式,只是轉換接口,后臺的數(shù)據(jù)仍是數(shù)組。
5、泛型通配符? extends T來接收返回的數(shù)據(jù),此寫法的泛型集合不能使用 add 方法, 而? super T不能使用 get 方法,做為接口調(diào)用賦值時易出錯。
說明: 擴展說一下 PECS(Producer Extends Consumer Super)原則:
1) 頻繁往外讀取內(nèi)容的,適合用上界 Extends。
?2) 經(jīng)常往里插入的,適合用下界 Super。
6、不要在 foreach 循環(huán)里進行元素的 remove/add 操作。 remove 元素請使用 Iterator方式,如果并發(fā)操作,需要對 Iterator 對象加鎖。
正例:
Iteratorit = a.iterator();
while (it.hasNext()) {
String temp = it.next();
if (刪除元素的條件) {
it.remove();
}
}
反例:
Lista = new ArrayList();
a.add("1");
a.add("2");
for (String temp : a) {
if ("1".equals(temp)) {
a.remove(temp);
}
}
7、集合初始化時, 指定集合初始值大小。
說明: HashMap 使用 HashMap(int initialCapacity) 初始化,
正例:initialCapacity = (需要存儲的元素個數(shù) / 負載因子) + 1。注意負載因子(即 loaderfactor) 默認為 0.75, 如果暫時無法確定初始值大小, 請設置為 16。
8、使用 entrySet 遍歷 Map 類集合 KV,而不是 keySet 方式進行遍歷。
說明: keySet 其實是遍歷了 2 次,一次是轉為 Iterator 對象,另一次是從 hashMap 中取出key 所對應的 value。而 entrySet 只是遍歷了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.foreach 方法。
正例: values()返回的是 V 值集合,是一個 list 集合對象; keySet()返回的是 K 值集合,是一個 Set 集合對象; entrySet()返回的是 K-V 值組合集合。
10、高度注意 Map 類集合 K/V 能不能存儲 null 值的情況,如下表格:
Hashtable不允許為 null不允許為 nullDictionary線程安全ConcurrentHashMap不允許為 null不允許為 nullAbstractMap分段鎖技術TreeMap不允許為 null允許為 nullAbstractMap線程不安全HashMap允許為 null允許為 nullAbstractMap線程不安全
反例: 由于 HashMap 的干擾,很多人認為 ConcurrentHashMap 是可以置入 null 值,而事實上,存儲 null 值時會拋出 NPE 異常。
控制語句
1、在 if/else/for/while/do 語句中必須使用大括號。 即使只有一行代碼,避免使用單行的形式: if (condition) statements;
2、表達異常的分支時, 少用 if-else 方式。如果非得使用 if()...else if()...else...方式表達邏輯,避免后續(xù)代碼維護困難, 請勿超過 3 層。
3、除常用方法(如 getXxx/isXxx)等外,不要在條件判斷中執(zhí)行其它復雜的語句,將復雜邏輯判斷的結果賦值給一個有意義的布爾變量名,以提高可讀性。
正例:
final boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
...
}
反例:
if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
}
異常處理
1、Java 類庫中定義的一類 RuntimeException 可以通過預先檢查進行規(guī)避,而不應該通過 catch 來處理,比如: IndexOutOfBoundsException, NullPointerException 等等。
正例: if (obj != null) {...}
反例: try { obj.method() } catch (NullPointerException e) {...}
2、異常不要用來做流程控制,條件控制,因為異常的處理效率比條件分支低。
3、有 try 塊放到了事務代碼中, catch 異常后,如果需要回滾事務,一定要注意手動回滾事務。
4、不能在 finally 塊中使用 return, finally 塊中的 return 返回后方法結束執(zhí)行,不會再執(zhí)行 try 塊中的 return 語句。
5、防止空指針異常,是程序員的基本修養(yǎng)。
6、避免出現(xiàn)重復的代碼(Don’t Repeat Yourself) ,即 DRY 原則。
說明: 隨意復制和粘貼代碼,必然會導致代碼的重復,在以后需要修改時,需要修改所有的副本,容易遺漏。必要時抽取共性方法,或者抽象公共類,甚至是共用模塊。
日志規(guī)約
1、應用中不可直接使用日志系統(tǒng)(Log4j、 Logback) 中的 API,而應依賴使用日志框架SLF4J 中的 API,使用門面模式的日志框架,有利于維護和各個類的日志處理方式統(tǒng)一。private static final Logger logger = LoggerFactory.getLogger(Abc.class);
2、日志文件推薦至少保存 15 天,因為有些異常具備以“周”為頻次發(fā)生的特點。
3、對 trace/debug/info 級別的日志輸出,必須使用條件輸出形式或者使用占位符的方式。說明: logger.debug("Processing trade with id: " + id + " symbol: " + symbol);如果日志級別是 warn,上述日志不會打印,但是會執(zhí)行字符串拼接操作,如果 symbol 是對象,會執(zhí)行 toString()方法,浪費了系統(tǒng)資源,執(zhí)行了上述操作,最終日志卻沒有打印。
正例: (條件)
if?(logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
}
正例: (占位符)
logger.debug("Processing trade with id: {} symbol : {} ", id, symbol);
4、避免重復打印日志,浪費磁盤空間,務必在 log4j.xml 中設置 additivity=false。
5、謹慎地記錄日志。生產(chǎn)環(huán)境禁止輸出 debug 日志; 有選擇地輸出 info 日志; 如果使用 warn 來記錄剛上線時的業(yè)務行為信息,一定要注意日志輸出量的問題,避免把服務器磁盤撐爆,并記得及時刪除這些觀察日志 。
其他
1、在使用正則表達式時,利用好其預編譯功能,可以有效加快正則匹配速度。
說明: 不要在方法體內(nèi)定義: Pattern pattern = Pattern.compile(規(guī)則);
2、后臺輸送給頁面的變量必須加$!{var}——中間的感嘆號。
說明: 如果 var=null 或者不存在,那么${var}會直接顯示在頁面上。
3、不要在視圖模板中加入任何復雜的邏輯。說明: 根據(jù) MVC 理論,視圖的職責是展示,不要搶模型和控制器的活。
4、任何數(shù)據(jù)結構的構造或初始化,都應指定大小,避免數(shù)據(jù)結構無限增長吃光內(nèi)存。
5、對于“明確停止使用的代碼和配置”,如方法、變量、類、配置文件、動態(tài)配置屬性等要堅決從程序中清理出去,避免造成過多垃圾。
6、SimpleDateFormat 是線程不安全的類,一般不要定義為 static 變量,如果定義為static,必須加鎖,或者使用 DateUtils 工具類。
正例: 注意線程安全,使用DateTools 。亦推薦如下處理:
public class DateTools
{
private static ThreadLocal t1=new ThreadLocal<>();
?public static SimpleDateFormat getSdf(String pattern){
?SimpleDateFormat simpleDateFormat = t1.get();
?if (simpleDateFormat==null){
simpleDateFormat=new SimpleDateFormat(pattern);
?}
?t1.set(simpleDateFormat);
?return simpleDateFormat;
}
}
?說明: 如果是 JDK8 的應用,可以使用 Instant 代替 Date, LocalDateTime 代替 Calendar,DateTimeFormatter代替Simpledateformatter,官方給出的解釋:simple beautiful strong immutable thread-safe。
讀到此刻
是不是覺得Java很偉大?Java如此重要,所以在排行榜的第一名也是當之無愧。
小編為大家準備了一套資料,方便大家的學習。資料整理不易

這里是Java程序員的交流群894180257,群里也為大家準備了很多資料,以及視頻,還有更多大佬講解。