contents
- 1. Java
- 1.1. Unique
- 1.2. toString in Comparison
- 1.3. toString() in Key
- 1.4. It is not in C++
- 1.5. Numeric Comparison
- 1.6. this in Constructor
- 1.7. Initialization
- 1.8. Find the Minimum/Maximum Element
- 1.9. Computed Getter
- 1.10. Computed If-Else
- 1.11. List Getter
- 1.12. Immutable Methods
- 1.13. Method Reference
- 1.14. Boxing
- 1.15. Exception is NOT a Return Value
- 1.16. Lightweight Exit
- 1.17. If-Elif-Else
- 1.18. Dead instanceof
- 1.19. Observer Pattern
- 1.20. Remove Observer
- 1.21. Opposite Behavior
- 1.22. Global Garbage
- 1.23. Useless Argument
- 1.24. Count
- 1.25. Tooltip
- 1.26. Convert Set to Array
- 1.27. Error Message
- 1.28. New Option
以下出現的問題,都是在公司遇到的事件,以類比的方式來描述遇到的狀況。
Java
Unique
|
|
對於唯一存在的物件,別用 compareTo()
來實作 equals()
,它們可以直接用 ==
判定。而且大部分的 compareTo
是比較慢的線性實作。如下述的物件
|
|
結果就是變得超慢。
toString
in Comparison
|
|
千萬別這麼幹,當我們對類別增加成員時,同時修改 toString()
後,運行結果也不同。這也會帶來嚴重的效能問題,試想著排序的時候,產生一大堆的字串用於比較,那麼垃圾回收就會佔有大部分的時間。
toString()
in Key
當需要對 enum
或者其他相關物件進行反序列時,避開 toString()
,因為這個函數很容易被其他人覆寫。
|
|
有人會說這個函數不該被覆寫,但能操作就可能出事。
It is not in C++
|
|
抱歉,您使用的是 Java,並沒有 operator==
的語法,所有的 ==
都是比較相同物件,並不會實作對應的 equals()
。
Numeric Comparison
|
|
這種容易發生 overflow/underflow 的寫法,並不建議模仿 C/C++ 的習慣,請多用內建的函數比較。
this
in Constructor
|
|
請盡量使用建構子,各自獨立容易漏掉一些共同的檢查。
Initialization
|
|
能使用建構子完成的事情就盡量使用,分次使用可能會造成過多額外的檢查或調整,效能就會往下掉。
Find the Minimum/Maximum Element
|
|
排序很簡單,但也不能亂寫。
排序複雜度大部分為 $O(n \log n)$,事實上找最小值只需要 $O(n)$。當 $n = 10^6$ 時,效率就可能差到 20 倍。
Computed Getter
|
|
請不要這麼寫,排版好看行數很多並不是好藉口,這呼叫了好幾次 getCPt()
,如果牽涉到好幾步複雜運算,整個效率就慢上了好幾倍。
Computed If-Else
|
|
寫在同一個 if-statement 很方便,卻造成效能嚴重退化。不如蠢一點的寫法,或者透過 Optional<>
來描述回傳型態。
|
|
List Getter
|
|
別鬧了,這會出大事。效能殺手就是你。LinkedList
的 get(index)
可是 $O(n)$ 的。
Immutable Methods
|
|
記得把回傳值接起來,請不要陡增效能問題。
Method Reference
|
|
盡量使用 method reference,防止 memory leak,也降低 lambda metafactory desugar 的花費。
Boxing
|
|
既然有預設值也確保不會發生 null
,請不要過度包裝。拆拆裝裝的狀況會造成垃圾過多。
Exception is NOT a Return Value
|
|
請別接收這麼奇怪的 runtime exception。在 Java 中,exception 很昂貴的,造價就是整個 call stack。
也別這樣追蹤物件的建立,大量物件會造成內存不足。
|
|
Lightweight Exit
|
|
別急著建立一堆用不著垃圾,有可能在後續判斷中直接返回。盡量縮小變數的生命週期,快用到的時候再準備計算資源。
If-Elif-Else
|
|
別說排版不重要,那一定是沒看過有人不小心漏了什麼。在大部分情況不太會出事,只是多判斷了幾次造成效能退化。
Dead instanceof
|
|
凡事有先後,請注意繼承關係。
Observer Pattern
|
|
當訂閱者數量不少,且容易進進出出,請不要用線性的 LinkedList
。當你需要嚴格地再現 BUG,就不要使用不穩定順序的 HashSet
,請使用 LinkedHashSet
是一種保守的選擇。
Remove Observer
|
|
別忘記移除掛載到資料庫的觀察者,這樣往往覆覆操作,越來越慢真的不能怪人。
Opposite Behavior
|
|
英文函數命名上,操作對稱就該對稱。英文不好要先說,邏輯不好也先說一聲,大家可以幫忙的。
Global Garbage
|
|
別擠壓到下一個人的生存空間,要是沒有使用 getXXX
,會看到一堆資料庫物件被卡在全區變數裡頭。
Useless Argument
|
|
別因為不想改動原本的,建立一個一模一樣名字的函數,而且第二個參數並沒有使用到,overloading 不是這樣子設計的。
Count
|
|
可以覺得慢,但不要總是開平行解決事情。這種計數問題,通常都有相關的方法可以呼叫。如果沒有,請聯絡相關人士。
Tooltip
|
|
沒人說這樣不好,除了串接消耗 $O(n^2)$,一般也不會把所有東西拉出來。
Convert Set to Array
|
|
建構子更方便,別這麼辛苦,效能至少慢了兩倍。
演算法還是有它的極限在的,常數的確不是很重要,但是數量一大的時候,均攤造成額外操作造成的垃圾,在 Java 中會變得相當明顯。
Error Message
|
|
人家還沒出錯,先別急著準備錯誤訊息。提前準備的字串複雜度比處理的複雜度還高,這絕不允許。
New Option
|
|
別再為了新參數往上疊,請用更容易看出參數意義的 builder 的寫法。
越來越多的參數,造成容易寫錯傳參的順序的悲劇,這時候 BUG