跳到主要內容

發表文章

目前顯示的是有「Java Method」標籤的文章

Effective Java - Methods

 這篇是收集觀看Effective Java針對Methods章節後所整理的心得。 Override clone judiciously Check parameters for validity & Use varargs judiciously Return empty collections or arrays, not nulls Return optionals judiciously

Effective Java - Return optionals judiciously

這個item主要告訴你使用Java 8推出的Optional的注意事項。本篇文章我以Java開發人員 Stuart Marks演講內容 與 投影片 中所提到的Rules去整理Effective Java與網路上的內容。 Rule#1: Never, ever, use null for an Optional variable or return value. 使用Optional的目的,是希望提供一個機制讓method回傳結果能夠表達“no result”,而不是透過null,因為null造成了很多的bug。以下為原文: Optional is intended to provide a limited mechanism for library method return types where there is a clear need to represent "no result," and where using null for that is overwhelmingly likely to cause errors. - From Stuart Marks' presentation 除此之外,也可以參考Java Language Architect - Brian Goetz的 說法 。 因此,當你讓Optional變數塞了null,或者是直接回傳null,就是脫褲子放屁;而在我們的production code中,還真的有這種code。 另外,Effective Java有提到適合使用Optional當method回傳值的使用時機: 是你的client需要針對空值做特別處理的時候。 Rule#2: Never use Optional.get() unless you can prove that the Optional is present. 第二個rule是要告訴你別直接使用Optional.get()去取得值,除非你確定它一定有值,如果使用sonarlint,會提示你至少要寫成這樣: Optional < User > searchResult = u...

Effective Java - Return empty collections or arrays, not nulls

這個item是要告訴你要回傳空collection或array,而不要回傳null;因為這會讓你client需要多處理null的情況,也多了需要被測試的路徑,而且也不會比較快。以書中的範例來說,針對collections回傳值的處理,會建議你使用以下方式: public List < Cheese > getCheeses ( ) { return new ArrayList <> ( cheesesInStock ) ; } Note. 這裡我不清楚作者為何要使用ArrayList,如果要immutable應該要用Collections.unmodifiableList。 作者提到有些反對這種做法的人,是基於產生empty collection的開銷,所以又提供了另外一種方式: public List < Cheese > getCheeses ( ) { return cheesesInStock. isEmpty ( ) ? Collections . emptyList ( ) : new ArrayList <> ( cheesesInStock ) ; } 透過Collections.emptyList取得的empty collection,是可以減少產生的開銷,但也代表你要多寫單元測試代碼;作者認為如果沒有證據表明這真的是一個效能問題,就請忽略它,以避免增加不必要的困擾。 針對Array的情況也是類似: public Cheese [ ] getCheeses ( ) { return cheesesInStock. toArray ( new Cheese [ 0 ] ) ; } 假如在意new Cheese[0]會造成效能問題,就用空間換時間吧! 另外作者有提到,千萬別寫以下方式,會因而產生效能問題: return cheesesInStock. toArray ( new Cheese [ cheesesInStock. size ( ) ] ) ; Note. 可以參考 此篇 詳細說明。 Reference: Effective Java, 3/e, Item 54。

Effective Java - Check parameters for validity & Use varargs judiciously

Use varargs judiciously varargs在我看這個item之前,我用的習以為常: public String appendStrings ( String ... strs ) { StringBuilder sb = new StringBuilder ( ) ; for ( String str : strs ) { sb. append ( str ) ; } return sb. toString ( ) ; } 後來某天和同事討論到strs輸入檢查的問題時,就回來翻閱了這個item。假如你要限制client必須輸入一個或多個參數時,在method內做限制檢查並不是一個好的設計;書中建議做法可以如下: public static String appendStrings ( String first, String ... strs ) { StringBuilder sb = new StringBuilder ( first ) ; for ( String str : strs ) { sb. append ( str ) ; } return sb. toString ( ) ; } 透過限制必須傳入一個參數的方式,可以降低有人傳空資料的機會。除此之外,書中提到使用這種方式可能會導致效能問題,因為每次的呼叫JVM都會針對內容做array的allocation與initialization。從網路上別人做實驗的文章中發現,速度大概慢了60倍。 針對client的呼叫有95%的機會少於三個參數的人,書中給了以下workaround: public void foo ( ) { } public void foo ( int a1 ) { } public void foo ( int a1, int a2 ) { } public void foo ( int a1, int a2, int a3 ) { } public void foo ( int a1, int a2, int a3, int ... rest ) { } 還特別舉了JDK中的EnumSe...

Effective Java - Override clone judiciously

Introduction 先說結論,這個Item其實是要勸你別Override Object.clone,而去使用Copy Constructor或Factory pattern去做clone。最近會回來重新看這篇,是由於同事override clone被SonarLint給找了出來,逼得我去研究他的寫法倒底是否合理。 既然是勸世文,當然要先從“如何寫正確的clone”開始。 Implement DeepCopy 假如你要複製的物件本身只有primitive的變數,那不會有太大問題,除非變數宣告為final。如果你要複製物件包含了非primitive的變數,但你沒有“特別處理”,那super.clone只會幫你把reference給複製過去,這稱為淺複製,也這意味著修改複製的內容會影響到原本的。 因此針對這些非primitive的變數,你必須一個欄位一個欄位複製。 Declare final class or final clone method 假如你有一個物件實做了clone,但沒宣告成final class or method,代表著你的sub-class有機會override這個clone: class A { public Object clone ( ) { return new A ( ) ; } }   class B extends A { public Object clone ( ) { return super . clone ( ) ; } } 在上面程式碼中,如果你用A去clone沒問題;但如果用B去clone,會因為你的A沒使用Object的clone而導致獲得的物件不是B。因此如果你Override了clone後,最好將其宣告為final。 其它問題 在Override clone時,會因為Object.clone會拋CloneNotSupportedException例外,而要去catch一條不會發生的例外;有final欄位時,你可能會選擇把final拿掉;使用super.clone時,你必須做type cast,也因此你必須對你的parent瞭若指掌。 使用Copy Constructor或Factory pattern ...