【03】Effective Java - 變量、類型、控制語句約定

一、將局部變量的做用域最小化

(1)在第一次使用它的地方聲明

        過早的聲明不只會使它做用域擴大,並且結束也過晚java

(2)聲明的時候包含一個初始化表達式

        若是在初始的時候,沒有足夠的信息對變量進行有意義的初始化,能夠推遲聲明,固然try catch例外git


 另外,一種使局部變量最小化的實踐是安全

for(int i=0,n=expensiveComputation();i<n;i++){
    doSomething(i);
}


二、優先使用for循環替代while循環

enum Face { ONE, TWO, THREE, FOUR, FIVE, SIX }

public class DiceRolls {
    public static void main(String[] args) {
        Collection<Face> faces = Arrays.asList(Face.values());

        for (Iterator<Face> i = faces.iterator(); i.hasNext(); )
            for (Iterator<Face> j = faces.iterator(); j.hasNext(); )
                System.out.println(i.next() + " " + j.next());

        // Preferred idiom for nested iteration on collections and arrays
//      for (Face face1 : faces)
//          for (Face face2 : faces)
//              System.out.println(face1 + " " + face2);
    }
}

  while容易出錯,並且變量範圍大數據結構

Iterator<Element> i = c.iterator();
while(i.hasNext()){
   doSomething(i.next());
}

for(Iterator<Element> i =c.iterator();i.hasNext();){
   doSomething(i.next());
}
...

Iterator<Element> i2 = c2.iterator();
//BUG,拷貝出錯了
while(i.hasNext()){
   doSomething(i.next());
}

//compile error
for(Iterator<Element> i2 =c2.iterator();i.hasNext();){
   doSomething(i.next());
}

 

三、for-each優先於傳統的for循環

(1)傳統的迭代器和索引
for(Iterator i = c.iterator();i.hasNext();){
   doSomething(i.next());
}

for(int i=0;i<a.length;i++){
   doSomething(a[i]);
}

//迭代器和索引變量容易引發一些混亂,特別是循環多層嵌套的狀況下

(2)for-each避免出錯
public class NestedIteration {
    public static void main(String[] args) {
        Collection<Suit> suits = Arrays.asList(Suit.values());
        Collection<Rank> ranks = Arrays.asList(Rank.values());

        List<Card> deck = new ArrayList<Card>();
        //BUG,NoSuchElementException
        for (Iterator<Suit> i = suits.iterator(); i.hasNext(); )
            for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
                deck.add(new Card(i.next(), j.next()));

        // Preferred idiom for nested iteration on collections and arrays
//        for (Suit suit : suits)
//            for (Rank rank : ranks)
//                deck.add(new Card(suit, rank));
    }
}

(3)沒法使用for循環的狀況

A、過濾條件,可使用iterator的remove方法app

B、須要使用索引值的狀況框架


四、精確值避免使用float和double

(1)float和double不適合貨幣計算

它們執行二進制浮點運算,爲了在普遍的數值範圍上提供較爲精確的快速近似計算而精心設計的,但沒有提供精確的結果,不適合須要精確值的貨幣計算。性能


(2)使用BigDecimal,int,long進行貨幣計算

用BigDecimal替代double,很差的地方就是與基本類型作比較相對麻煩,並且比較慢。優化

public class Arithmetic {
    public static void main(String[] args) {
        System.out.println(1.03 - .42);
        System.out.println();

        System.out.println(1.00 - 9 * .10);
        System.out.println();

        howManyCandies1();
        System.out.println();

        howManyCandies2();
        System.out.println();

        howManyCandies3();
    }

    // Broken - uses floating point for monetary calculation!
    public static void howManyCandies1() {
        double funds = 1.00;
        int itemsBought = 0;
        for (double price = .10; funds >= price; price += .10) {
            funds -= price;
            itemsBought++;
        }
        System.out.println(itemsBought + " items bought.");
        System.out.println("Change: $" + funds);
    }

    public static void howManyCandies2() {
        final BigDecimal TEN_CENTS = new BigDecimal( ".10");

        int itemsBought = 0;
        BigDecimal funds = new BigDecimal("1.00");
        for (BigDecimal price = TEN_CENTS;
             funds.compareTo(price) >= 0;
             price = price.add(TEN_CENTS)) {
            itemsBought++;
            funds = funds.subtract(price);
        }
        System.out.println(itemsBought + " items bought.");
        System.out.println("Money left over: $" + funds);
    }

    public static void howManyCandies3() {
        int itemsBought = 0;
        int funds = 100;
        for (int price = 10; funds >= price; price += 10) {
            itemsBought++;
            funds -= price;
        }
        System.out.println(itemsBought + " items bought.");
        System.out.println("Money left over: "+ funds + " cents");
    }
}

(3)選擇建議

A、對於須要精確值的,請不要用float和doubleui

B、BigDecimal的好處是能夠進行四捨五入的控制spa

C、若是數值範圍沒有超過9位的十進制數,可使用int,若是不超過18位的十進制數,使用long,超過18位的,必須使用BigDecimal

D、若是性能比較關鍵,本身又不介意記錄小數值,涉及的數又不太大的話,可使用int或long


五、基本類型優於裝箱基本類型

(1)區別

A、基本類型只有值,而裝箱基本類型有引用的概念,容許值相等可是引用不等

B、基本類型只有功能完備的值,而裝箱類型,有null值

C、基本類型比裝箱類型更節省時間和空間


(2)對裝箱類型使用==幾乎都是錯誤的
Integer i;
....
if(i == 42){
   
}

//可能報空指針錯誤,由於若是沒有賦值,如果類成員,默認爲null,不能夠用== 跟int比較

//但另外,裝箱類型與原始類型進行比較,只要不是null,能夠自動拆箱

//Integer first,Integer second
if(first == second){
   //這裏是引用比較,不是值比較
}


(3)使用裝箱類型的狀況

A、做爲集合元素、鍵值時

B、參數泛型時


六、有其餘更合適類型時,避免使用字符串

(1)字符串不適合替代其餘的值類型

A、若是是數值,用int、float、BigInteger類型

B、若是是布爾,用true/false


(2)字符串不適合替代枚舉類型

   枚舉類型更適合用來表示常量


(3)字符串不適合替代彙集類型
String compoundKey = className + "#" + i.next();

   這種狀況,容易出現結果混亂,一般解析的時候,過程相對緩慢,繁瑣,容易出錯,使用Scala的Case類的模式匹配正好。


(4)字符串不適合替代能力表

  儘可能使用泛型


七、小心字符串的鏈接性能

(1)不可變性

   爲鏈接n個字符串並且重複地使用字符串鏈接操做符,須要n的平方級的時間

(2)使用StringBuilder替代

   在方法裏頭,用StringBuilder,若是是類成員範圍的,若是線程安全的話,須要StringBuffer,但通常不怎麼在類成員範圍內使用。於是StringBuilder足夠。


八、經過接口引用對象

List<String> list = new Vector<String>();

//優於
Vector<String> list = new Vector<String>();

  同理,在參數、返回值類型也適用。這樣作的目的,是能夠更改實現,特別是對外部系統暴露接口時,更改實現的時候,不須要調用方更改類型。


九、接口優先於反射

(1)反射的代價

A、喪失了編譯時類型檢查的好處

B、執行反射訪問所須要的代碼很是笨拙和冗長

C、性能損失


(2)建議

A、反射功能只是在設計時被用到,普通程序不該該在運行時以反射訪問對象

     好比容器初始化階段、好比在開發階段用代碼生成器生成增刪改查方法

B、以有限形式使用,能夠得到許多好處的狀況下,可使用

     好比遠程服務框架等


十、慎用本地方法

(1)本地方法用途

A、提供訪問特定於平臺的機制,好比訪問註冊表等

B、提供訪問遺留代碼庫的能力

C、經過本地語言提高系統性能

    這點不值得提倡,容易致使不可移植,以及代碼維護性問題


(2)缺點

A、本地語言不安全

B、本地方法難以調試

C、膠合代碼難以閱讀


十一、接受廣泛命名規則

(1)包名應該是層次性的

      com.sun等,以Internet域開頭

(2)包名鼓勵使用有意義的縮寫

     使用util替代utilities

(3)對於縮寫字符,建議僅首字母大寫

    使用HttpUrl替代HTTPURL

(4)常量用大寫加下劃線

    NEGATIVE_INFINITY

(5)泛型經常使用的表達字母

    T表示任意的類型,E表示集合的元素類型,K和V表示映射的鍵值類型,X表示異常

    類型序列可使用T,U,V,或者T1,T2,T3

(6)幾種常見命名

A、執行動做的方法,經常使用動詞或動詞短語了來命名,好比append,drawImage

B、布爾值,常以is開頭後面跟名稱或名稱短語,不多用has

     isDigit,isProbablePrime,isEmpty,isEnabled,hasSiblings

C、類型轉換,使用toType命名,好比toString,toArray

D、返回視圖,使用asType,好比asList

E、返回基本類型,使用typeValue,好比intValue

F、靜態工廠常用valueOf,of,getInstance,newInstance,getType,newType


十二、謹慎進行優化

(1)API設計時考慮性能

    特別是設計數據結構的時候,若是合理,能夠避免不變要的join

(2)優化先後要進行測量

     考慮優化的重心在哪裏

相關文章
相關標籤/搜索