Java基礎學習總結(91)——阿里巴巴Java開發手冊公開版

1.不要嫌名字長

不管是方法,變量,仍是函數的取名,不要嫌棄名稱太長,只要可以表示清楚含義就能夠了。java

2.String[] args而不是String args[]

中括號是數組類型的一部分,數組定義以下:String[] args;算法

在《Thinking in Java》這邊書裏面,是這麼解釋的:spring

  • 大部分開發人員,習慣前一種寫法。
  • 前一種寫法符合咱們的口語化,咱們口語一般都說:定義一個字符串數組(String 代碼字符,[]表明數組)
3.POJO 類中的任何布爾類型的變量,都不要加is

POJO類中的任何布爾類型的變量,都不要加 is,不然部分框架解析會引發序列化錯 
誤。
數據庫

大部分經典的書籍都有提到這一點,老話題了。apache

4.各層命名規約

A) Service/DAO 層方法命名規約 
1) 獲取單個對象的方法用 get 作前綴。 
2) 獲取多個對象的方法用 list 作前綴。 
3) 獲取統計值的方法用 count 作前綴。 
4) 插入的方法用 save(推薦)或 insert 作前綴。 
5) 刪除的方法用 remove(推薦)或 delete 作前綴。 
6) 修改的方法用 update 作前綴。
編程

這一點確實很重要,有時候本身都作不到,規範大於編碼windows

5.不容許出現任何魔法值(即未經定義的常量)
String key="Id#taobao_"+tradeId; cache.put(key, value); 

魔法數值:是指在代碼中直接出現的數值,而只有在這個數值記述的那部分代碼中才能明確瞭解其含義。設計模式

在這裏進行擴充下:api

魔法數字的例子數組

  int priceTable[] = new int[16]; //ERROR:這個16究竟有何含義呢?

  使用了帶名字的數值的例子

解決方法:

static final int PRICE_TABLE_MAX = 16; //OK:帶名字 

  int price Table[] = new int [PRICE_TABLE_MAX]; //OK:名字的含義是很清楚的

6.多個參數逗號後邊必須加空格

有時候作項目,心急如焚時,就會忘記

下例中實參的」a」,後邊必需要有一個空格

method("a", "b", "c"); 
7.開發工具編碼設置

IDE 的 text file encoding 設置爲 UTF-8; IDE 中文件的換行符使用 Unix 格式,不 
要使用 windows 格式

8.全部的覆寫方法,必須加@Override註解

若是在抽象類中對方法簽名進行修改,其實現類會立刻編 
譯報錯

《Effective Java》這本書已經說的清清楚楚了,你們能夠去啃啃這一節的內容。

9.提倡儘可能不用可變參數編程

相同參數類型,相同業務含義,纔可使用Java的可變參數,避免使用 Object。可變參數必須放置在參數列表的最後

public User getUsers(String type, Integer... ids); 
10.基本數據類型與包裝數據類型的使用標準

1) 全部的POJO類屬性必須使用包裝數據類型。 
2) RPC方法的返回值和參數必須使用包裝數據類型。 
3) 全部的局部變量推薦使用基本數據類型。 
說明:POJO類屬性沒有初值是提醒使用者在須要使用時,必須本身顯式地進行賦值,任何 
NPE 問題,或者入庫檢查,都由使用者來保證。 
正例:數據庫的查詢結果多是 null,由於自動拆箱,用基本數據類型接收有 NPE 風險。 
反例:某業務的交易報表上顯示成交總額漲跌狀況,即正負 x%,x 爲基本數據類型,調用的 
RPC 服務,調用不成功時,返回的是默認值,頁面顯示:0%,這是不合理的,應該顯示成中劃 
線-。因此包裝數據類型的 null 值,可以表示額外的信息,如:遠程調用失敗,異常退出

11.序列化類新增屬性時,請不要修改serialVersionUID字段

避免反序列失敗

12.構造方法裏面禁止加入任何業務邏輯

若是有初始化邏輯,請放在init方法中

其實這是符合一個方法只作一件事的原則

13.POJO 類必須寫 toString 方法

使用工具類 source> generate toString 時,若是繼承了另外一個 POJO 類,注意在前面加一下 super.toString。說明:在方法執行拋出異常時,能夠直接調用 POJO 的 toString()方法打印其屬性值,便於排查問題。

貌似咱們項目框架中,這一點沒有作到

14.同名的或者類似的方法放置在一塊兒
15.類內方法定義順序

類內方法定義順序依次是:公有方法或保護方法 > 私有方法 > getter/setter 方法。

說明: 公有方法是類的調用者和維護者最關心的方法,首屏展現最好;保護方法雖然只是子類 
關心,也多是「模板設計模式」下的核心方法;而私有方法外部通常不須要特別關心,是一 
個黑盒實現;由於方法信息價值較低,全部 Service 和 DAO 的 getter/setter 方法放在類體最 
後。

16.final可提升程序響應效率

final可提升程序響應效率,聲明成final的狀況: 
1) 不須要從新賦值的變量,包括類屬性、局部變量。 
2) 對象參數前加final,表示不容許修改引用的指向。 
3) 類方法肯定不容許被重寫

17.Map/Set的key爲自定義對象時,必須重寫hashCode和equals

String 重寫了 hashCode 和 equals 方法,因此咱們能夠很是愉快地使用String對象做 
爲 key 來使用。

18.使用集合轉數組的方法,必須使用集合的 toArray(T[] array)

傳入的是類型徹底同樣的數組,大小就是 list.size()。

反例:直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[]類,若強轉其它 
類型數組將出現 ClassCastException 錯誤。

正例:

List<String> list = new ArrayList<String>(2); list.add("guan"); list.add("bao"); String[] array = new String[list.size()]; array = list.toArray(array); 

說明:使用 toArray 帶參方法,入參分配的數組空間不夠大時,toArray 方法內部將從新分配 
內存空間,並返回新數組地址;若是數組元素大於實際所需,下標爲[ list.size() ]的數組 
元素將被置爲 null,其它數組元素保持原值,所以最好將方法入參數組大小定義與集合元素 
個數一致

19.Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關的方法

它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。 
說明: asList 的返回對象是一個 Arrays 內部類,並無實現集合的修改方法。 Arrays.asList 
體現的是適配器模式,只是轉換接口,後臺的數據還是數組。

String[] str = new String[] { "a", "b" }; List list = Arrays.asList(str); 第一種狀況:list.add("c"); 運行時異常。 第二種狀況:str[0]= "gujin"; 那麼 list.get(0)也會隨之修改。 
20.不要在foreach循環裏進行元素的remove/add操做

remove元素請使用Iterator方式,若是併發操做,須要對 Iterator 對象加鎖。

反例: 
List a = new ArrayList(); 
a.add(「1」); 
a.add(「2」); 
for (String temp : a) { 
if(「1」.equals(temp)){ 
a.remove(temp); 

}

21.集合初始化時,儘可能指定集合初始值大小

ArrayList 儘可能使用 ArrayList(int initialCapacity) 初始化。

22.使用entrySet遍歷Map類集合KV,而不是keySet

keySet 實際上是遍歷了 2 次,一次是轉爲 Iterator 對象,另外一次是從 hashMap 中取出 key 
所對應的 value。而 entrySet 只是遍歷了一次就把 key 和 value 都放到了 entry 中,效率更 
高。若是是 JDK8,使用Map.foreach 方法。

這一點能夠參考《Thinking in Java》第17章容器深刻研究這一章

23.利用Set元素惟一的特性,能夠快速對另外一個集合進行去重操做

避免使用List的contains 方法進行遍歷去重操做。

24.數據庫合適的字符存儲長度

不但節約數據庫表空間、節約索引存儲,更重要的是提高檢索速度。

25.在表查詢中,一概不要使用 * 做爲查詢的字段列表

須要哪些字段必須明確寫明。

說明:1)增長查詢分析器解析成本。2)增減字段容易與resultMap配置不一致。

26.in操做能避免則避免

若實在避免不了,須要仔細評估 in 後邊的集合元素數量,控制在 1000 個以內。

27.異常信息應該包括兩類信息

異常信息應該包括兩類信息:案發現場信息和異常堆棧信息。若是不處理,那麼往上 
拋。

logger.error(各種參數或者對象 toString + "_" + e.getMessage(), e); 
28.if/else/for/while/do 語句中必須使用大括號,即便只有一行代碼

這一點我有點不支持,好比下面的代碼:

//阿里巴巴建議的寫法 if(a > 0){ System.out.println("....."); } //對於if邏輯中只有一句話,我習慣下面這麼些 if(a > 0) System.out.println("....."); 

那個比較好本身對比吧!!!

29.禁止使用存儲過程

存儲過程難以調試和擴展,更沒有移植性

反正咱們公司沒用。

30.推薦儘可能少用 else, if-else的方式能夠改寫成
if(condition){ … return obj; } 

事實上這個是《重構-改善既有代碼設計》這本書所提倡的,多些衛語句,具體什麼是衛語句,我在下面參考文章中有一篇連接,你們能夠去看。

31.不要在條件判斷中執行復雜的語句

正例:

//僞代碼以下 InputStream stream = file.open(fileName, "w"); if (stream != null) { … } 

反例: 
if (file.open(fileName, 「w」) != null)) { 
… 
}

32.線程安全相關的類使用

SimpleDateFormat 是線程不安全的類,通常不要定義爲 static 變量,若是定義爲static,必須加鎖,或者使用 DateUtils 工具類。

正例:注意線程安全,使用 DateUtils。亦推薦以下處理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } }; 

說明:若是是 JDK8 的應用,可使用 instant 代替 Date,Localdatetime 代替 Calendar, 
Datetimeformatter 代替 Simpledateformatter,官方給出的解釋:simple beautiful strong 
immutable thread-safe。

避免 Random 實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一 seed 
致使的性能降低。 
說明:Random 實例包括 java.util.Random 的實例或者 Math.random()實例。 
正例:在 JDK7 以後,能夠直接使用 API ThreadLocalRandom,在 JDK7 以前,能夠作到每一個線 
程一個實例。

33.類、類屬性、類方法的註釋必須使用 javadoc 規範

類、類屬性、類方法的註釋必須使用 javadoc 規範,使用/*內容/格式,不得使用//xxx 方式。

方法內部單行註釋,在被註釋語句上方另起一行,使用//註釋。方法內部多行註釋使 
用/* */註釋,注意與代碼對齊

能夠參考《代碼整潔之道》這本書中的註釋這一章,裏面內容更加纖細。

34.刪除被註釋掉的沒用的東西

對於「明確中止使用的代碼和配置」,如方法、變量、類、配置文件、動態配置屬性 
等要堅定從程序中清理出去,避免形成過多垃圾。清理這類垃圾代碼是技術氣場,不要有這樣 
的觀念:「不作不錯,多作多錯」。

35.獲取當前毫秒數:System.currentTimeMillis()

而不是 new Date().getTime();

說明:若是想獲取更加精確的納秒級時間值,用 System.nanoTime。在 JDK8 中,針對統計時 
間等場景,推薦使用 Instant 類。

【強制】線程資源必須經過線程池提供,不容許在應用中自行顯式建立線程。 
說明: 使用線程池的好處是減小在建立和銷燬線程上所花的時間以及系統資源的開銷,解決資 
源不足的問題。若是不使用線程池,有可能形成系統建立大量同類線程而致使消耗完內存或者 
「過分切換」的問題。

36.全部的類都必須添加建立者信息。

事實上,我我的建議,每一個方法都要寫上建立者姓名,這樣出現問題比較好排查

出現問題,分分鐘弄死它。

37.代碼修改的同時,註釋也要進行相應的修改

尤爲是參數、返回值、異常、核心邏輯等的修改。

38.任何數據結構的使用都應限制大小

說明:這點很難徹底作到,但不少次的故障都是由於數據結構自增加,結果形成內存被吃光。

39.日誌文件推薦至少保存 15 天

由於有些異常具有以「周」爲頻次發生的特色。

40.對trace/debug/info級別的日誌輸出,必須使用條件輸出形式

或者使用佔位符的方式。

說明:logger.debug(「Processing trade with id: 」 + id + 」 symbol: 」 + symbol); 若是 
日誌級別是 warn,上述日誌不會打印,可是會執行字符串拼接操做,若是 symbol 是對象,會 
執行 toString()方法,浪費了系統資源,執行了上述操做,最終日誌卻沒有打印。

正例:(條件)

if (logger.isDebugEnabled()) { logger.debug("Processing trade with id: " + id + " symbol: " + symbol); } 

正例:(佔位符)

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol); 
41.特殊註釋標記,請註明標記人與標記時間

注意及時處理這些標記,經過標記掃描,常常清理此類標記。線上故障有時候就是來源於這些標記處的代碼。

  • 1) 待辦事宜(TODO):( 標記人,標記時間,[預計處理時間]) 
    表示須要實現,但目前還未實現的功能。這其實是一個 javadoc 的標籤,目前的 
    javadoc 尚未實現,但已經被普遍使用。 只能應用於類,接口和方法(由於它是一個 javadoc 
    標籤)。
  • 2) 錯誤,不能工做(FIXME):(標記人,標記時間,[預計處理時間]) 
    在註釋中用 FIXME 標記某代碼是錯誤的,並且不能工做,須要及時糾正的狀況。
42.避免用Apache Beanutils 進行屬性的 copy

說明:Apache BeanUtils 性能較差,可使用其餘方案好比 spring BeanUtils, Cglib 
BeanCopier。

之後會專門寫一篇關於這方面的文章,敬請期待

43.注意HashMap的擴容死鏈

致使 CPU 飆升的問題

44.應用中的擴展日誌(如打點、臨時監控、訪問日誌等)命名方式

appName_logType_logName.log。logType:日誌類型,推薦分類有 stats/desc/monitor/visit 
等;logName:日誌描述。這種命名的好處:經過文件名就可知道日誌文件屬於什麼應用,什麼類型,什麼目的,也有利於歸類查找。

45.高併發時,同步調用應該去考量鎖的性能損耗

能用無鎖數據結構,就不要用鎖;能鎖區塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。

46在代碼中使用「拋異常」仍是「返回錯誤碼」

對於公司外的 http/api 開放接口必須使用「錯誤碼」;而應用內部推薦異常拋出;跨應用間 RPC 調用優先考慮使用 Result 方式,封裝 isSuccess、「錯誤碼」、「錯誤簡短信息」。

說明:關於 RPC 方法返回方式使用 Result 方式的理由: 
1)使用拋異常返回方式,調用方若是沒有捕獲到就會產生運行時錯誤。 
2)若是不加棧信息,只是 new 自定義異常,加入本身的理解的 error message,對於調用 
端解決問題的幫助不會太多。若是加了棧信息,在頻繁調用出錯的狀況下,數據序列化和傳輸 
的性能損耗也是問題。

47.謹慎地記錄日誌。生產環境禁止輸出 debug 日誌

有選擇地輸出 info 日誌;若是使用 warn 來記錄剛上線時的業務行爲信息,必定要注意日誌輸出量的問題,避免把服務器磁盤撐爆,並記得及時刪除這些觀察日誌。

說明:大量地輸出無效日誌,不利於系統性能提高,也不利於快速定位錯誤點。紀錄日誌時請 
思考:這些日誌真的有人看嗎?看到這條日誌你能作什麼?能不能給問題排查帶來好處?

48.單錶行數超過 500 萬行或者單表容量超過 2GB,才推薦進行分庫分表。
相關文章
相關標籤/搜索