天天看點

3分鐘快速閱讀-《Effective Java》(五)

41.慎用重載

使用重載時有些重載方法并不會根據你想要的方式來進行運作的,編譯器會根據自己想要的最簡便的方式來運作對應的方法,如下所示
public class CollectionClassFind {

    public static String classFind(List<?> list){
        return "List";
    }
    public static String classFind(Set<?> set){
        return "Set";
    }
    public static String classFind(Collection<?> collection){
        return "Collection";
    }

    public static void main(String[] args) {
        Collection<?>[] collections = {
          new HashSet(),new ArrayList(), new HashMap().values()
        };
        for (Collection collection : collections) {
            System.out.println(classFind(collection));
        }
        //理想結果:List Set Collection
        //實際結果:Collection Collection Collection
    }
}
      
簡而言之,能夠重載方法并不意味着應該重載方法.如果一定要進行方法重載,那麼就要考慮是否會被編譯器所忽略

42.慎用可變參數

當我們需要定義參數數目不定的方法時,可變參數時一種很友善的方式,但是不應該被過度濫用,參數清單不應該隻有一個可變參數,避免調用方一個參數也不傳導緻程式出現問題.應該如下所示,用一個固定參數來進行區分
  • 錯誤做法
public static void main(String[] args) {
        int sum = sum();
        System.out.println(sum);
    }
    public static int sum(int... args){
        int sum = 0;
        for (int arg : args) {
            sum += arg;
        }
        return sum;
    }
      
  • 正确做法
public static void main(String[] args) {
        int sum = sum(1, 3, 4, 5, 6, 7, 8, 9);
        System.out.println(sum);
    }
    public static int sum(int first,int... args){
        for (int arg : args) {
            first = first + arg;
        }
        return first;
    }
      

43.傳回0長度的數組或者集合,而不是null

如果方法傳回集合是抛給一個null,那麼就會需要調用方來處理這個問題,此時我們應該盡可能的自己來解決這個異常,以避免給調用者帶來不必要的麻煩
private final List<Cheese> cheeses = new ArrayList<>(10);
    public List<Cheese> getCheeses(){
        if(cheeses.size() == 0){
            return null;
        }
        return cheeses;
    }
      
private final List<Cheese> cheeses = new ArrayList<>(10);
    public List<Cheese> getCheeses(){
        if(cheeses.size() == 0){
            return null;
        }
        return Collections.EMPTY_LIST;
    }
      

44.為所有導出的API元素編寫文檔注釋

這一條沒什麼好解釋的,需要我們習慣性的去執行即可

45.将局部變量的作用域最小化

原文釋義:早期程式的設計會要求在方法開始的時候就把所有需要用到的局部變量都進行生命,但是這樣會導緻程式的可讀性降低,最好的做法是當局部變量需要用到的時候去使用它.
其實我覺得如果每個方法都能非正常範的把局部變量的聲明寫在最前面,這樣也是可友善方法的閱讀的.但是如果想要真正的提高一個方法的可讀性,就需要我們把方法設計的小而集中,這才是解決問題的本質做法

46.foreach循環優先于傳統的for循環

使用foreach循環好處是相比于傳統for循環并沒有性能損耗,并且比較不容易出現BUG或者寫錯循環次數導緻索引越界的問題
  • 以下三種情況無法使用foreach
    • 過濾:需要在集合當中删除標明的元素
    • 轉換:需要取代集合當中的某個元素
    • 平行疊代:需要并行的周遊多個集合,需要顯示控制疊代器或者索引變量,一遍所有疊代器或者索引變量都可以得到同步前移

47.了解和使用類庫

引用原文:不要重新發明輪子,如果你要做的事情看起來是十分常見的
Java發展至今正常可能遇到的需求工具類,不要着急自己寫一個,首先先找Java自帶的util包下看看有沒有,如果沒有就到谷歌的common.lang3下的util包下,或者Spring社群當中也出了很多的工具包.隻要是Spring相關的項目,引入簡便,使用起來也十分輕松

48.如果需要精确的答案,請避免使用float和double

public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        BigDecimal sum = BigDecimal.ZERO;
        for(int i =0; i<=10000;i++){
            sum = sum.add(new BigDecimal(1));
        }
        long end = System.currentTimeMillis();
        System.out.println("BigDecimal總耗時:"+(end - begin)+"結果:"+sum);//5ms

        long begin1 = System.currentTimeMillis();
        double sum1 = 0;
        for(int i =0; i<=10000;i++){
            sum1 = sum1 + 1;
        }
        long end1 = System.currentTimeMillis();
        System.out.println("double總耗時:"+(end1 - begin1)+"結果:"+sum1);//0ms

    }
      

49.基本類型優先于裝箱基本類型

  • 49.1 裝箱基本類型屬于引用類型,會在堆空間開辟一塊新的記憶體空間,相比于基本類型,更加消耗性能,當計算次數越大,差别将會越明顯
public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        Integer sum = 0;
        for(int i =0; i<=1000000;i++){
            sum = sum + 1;
        }
        long end = System.currentTimeMillis();
        System.out.println("Integer總耗時:"+(end - begin)+"ms,結果:"+sum);//10ms

        long begin1 = System.currentTimeMillis();
        int sum1 = 0;
        for(int i =0; i<=1000000;i++){
            sum1 = sum1 + 1;
        }
        long end1 = System.currentTimeMillis();
        System.out.println("int總耗時:"+(end1 - begin1)+"ms, 結果:"+sum1);//0ms
    }
      
  • 49.2 裝箱基本類型和基本資料類型混合使用的時候,JVM編譯器的自動拆裝箱容易導緻空指針異常,是以使用時記得類型的一緻性保證
  • 49.3 裝箱基本類型使用==比較的結果是比較兩者在堆空間的位址值,這是不準确的

50.如果其他類型更适合,則盡量避免使用字元串

  • 50.1 字元串不适合代替其他的值類型.不要試圖用String去替代int,double,boolean這些基本類型就能完成的事情
  • 50.2 字元串不适合代替枚舉類型.枚舉類型的一個大的特點就是簡潔且安全,相比之下字元串都不具有這樣的優勢
  • 50.3 字元串不适合代替聚集類型.即是不要使用String的+号來拼接而形成一個新的字元串