聲明:原創作品,轉載時請注明文章來自SAP師太技術博客( 博/客/園www.cnblogs.com):m.survivalescaperooms.com/jiangzhengjun,并以超鏈接形式標明文章原始出處,否則將追究法律責任!原文鏈接:http://m.survivalescaperooms.com/jiangzhengjun/p/4255680.html 第八章 通用程序設計45、 將局部變量的作用域最小化將局部變量的作用域最小化,可以增強代碼的可讀性和可維護性,并降低出錯的可能性。
要使用局部變量的作用域最小化,最有力的方法就是在第一次使用它的地方才聲明,不要過早的聲明。
局部變量的作用域從它被聲明的點開始擴展,一直到外圍塊的結束外。如果變量是在“使用它的塊”之外被聲明有,當程序退出該塊之后,該變量仍是可見的,如果它在目標使用區之前或之后意外使用,將可能引發意外錯誤。
幾乎每個局部變量的聲明都應該包含一個初始化表達式,如果你還沒有足夠信息來對象一個變量進行有意義的初始化,就應該推遲這個聲明,直到可初始化為止。但這條規則有個例外的情況與try-catch語句有關。如果一個變量被一個方法初始化,而這個方法可能會拋出一個檢測性異常,該變量就必須在try塊內部被初始化。如果變量的值必須在try塊的外部使用到,它就必須在try塊之前被聲明,但是在try塊之前,它還不能“有意義地初始化”,請參照第53條中的異常實例。
循環中提供了特殊的機會來將變量的作用域最小化。如果在循環終止之后不再需要使用循環變量的內容,for循環就優先于while循環。例如,下面是一種遍歷集合的首選做法:
for(Element e: c){
doSomething(e);
}
在1.5前,首先做法如下:
for(Iterator i = c.iterator();i.hasNext();){
doSomething((Element) i.next());
}
為了弄清為什么這個for循環比while循環更好,請看下面代碼:
Iterator<Element> i = c.iterator();
while(i.hasNext()){
doSomething(i.next());
}
…
Iterator<Element> i2 = c2.iterator();
while(i.hasNext()){//Bug!
doSomething(i2.next());
}
CP過來的代碼未修改完,結果導致for循環編譯通不過。
最后一種“將局部變量的作用域最小化”的方法是使方法小而集中。
----------------------
補充,不能在while條件中聲明變量,這與for循環不一樣,也不能像下面這樣在while體中聲明一個變量:
while(true)
int i = 1;
只可以這樣:
while(true){
int i = 1;
}
46、 for-each循環優先于傳統的for循環1.5前,遍歷集合的首選做法如下:
for(Iterator i = c.iterator(); i.hasNext();){
doSomething((Element)i.next());
}
遍歷數組的首選做法如下:
for(int i =0; i < a.length;i++){
doSomething(a[i]);
}
雖然這些做法比while循環理好,但并不完美,因為迭代器和索引變量在每個循環中出現三次,其中有兩次讓你出錯。
1.5中完全隱藏迭代器或者索引變量,避免了混亂和出錯的可能,下面這種模式同樣適合于集合與數組:
for(Element e : elements){
doSomething(e);
}
集合內嵌迭代時問題:
Collection<Suit> suits = ...;
Collection<Rank> ranks = ...;
List<Card> deck =...;
for(Iterator<Suit> i = suits.iterator(); i.hasNext();)
for(Iterator<Rank> j = ranks.iterator(); j.hasNext();)
deck.add(newCard(i.next(), j.next()));//i.next在內部循環中多次調用,會出現問題
將i.next()臨時存儲起來可以解決這個問題:
for(Iterator<Suit> i = suits.iterator(); i.hasNext();){
Suit suit = i.next();
for(Iterator<Rank> j = ranks.iterator(); j.hasNext();)
deck.add(newCard(suit, j.next()));
}
如果使用內嵌的for-each循環,這個問題很快會完全消失,代碼是如此的簡潔:
for(Suit suit : suits)
for(Rank rank : ranks)
deck.add(newCard(suit, rank));
for-each循環不僅讓你遍歷集合數組,還讓你遍歷任何實現Iteralble接口的對象。這個簡單的接口接口由單個方法組成,與for-each循環同時被增加到Java平臺中,這個接口如下:
public interface Iterable<E>{
Iterator<E> iterator();
}
總之,for-each循環在簡潔性和預防Bug方面有著傳統的for循環無法比擬的優勢,并且沒有性能損失。應該盡可能地使用for-each循環,遺憾的是,有些情況是不適用的,比如需要顯示地得到索上或迭代器然后進行其他操作,或者是內部循環的條件與外部有直接關系的(比如內層循環的起始值依賴于外層循環的條件值)。
47、 了解和使用類庫假如你希望產生位于0和某個上界之間的隨機整數,你可以會這么做:
PRivae static final Random rnd = new Random();
static int random(int n){
return Math.abs(rnd.nextInt())%n;
}
上面程序產生的0到n間的整數是不均的,使用類庫中的Random類的nextInt(Int)可以解決,這些方法是經過專家們設計,并經過多次測試和使用過的方法,比我們自己實現可靠得多。
通過使用標準類庫,可以充分利用這些編寫標準類庫的專家的知識,以及在你之前的其他人的使用經驗。
使用標準類庫中的第二個好處是,不必關心底層細節上,把時間應花在應用程序上。
使用標準類庫中的第三個好處是,它們的性能往往會隨著時間的推移而不斷提高,無需你做任何努力。
本條目不可能總結類庫中所有便利工具,但是有兩種工具值得特別一提。一個是1.2發行版本中的集合框架,二是1.5版本中,在java.util.concurrent包中增加了一組并發實用工具,這個包既包含高級的并發工具來簡化多線程的編程任務,還包含低級別的并發基本類型,允許專家們自己編寫更高級的并發抽象,java.util.concurrent的高級部分,也應該是每個程序員基本工具箱中的一部分。
總之,不要重新發明輪子,已存在的我們就直接使用,只有不能滿足我們需求時,才需自己開發,總的來說,多了解類庫是有好處的,特別是為庫中的工具包。
48、 如果需要精確的答案,請避免使用float和doublefloat和double類型主要是用來為科學計算和工程計算而設計的。它們執行二進制浮點運算,這是為了在廣泛的數值滿園上提供較為精確的快速近似計算而精心設計的,然而,它們并沒有提供完全精確的結果,所以不應該被用于需要精確結果的場合。float和double類型尤其不適合用于貨幣的計算,因為要讓一個float和double精確地表示0.1(或者10的任何其他負數次方值)是不可能的。
System.out.println(1.0-.9);//0.09999999999999998
請使用BigDecimal、int或long(int與long以貨幣最小單位計算)進行貨幣計算。
使用BigDecimal時請還請使用BigDecimal(String),而不要使用BigDecimal(float或double),因為后者在傳遞的過程中會丟失精度:
newBigDecimal(0.1)//0.1000000000000000055511151231257827021181583404541015625
new BigDecimal("0.1")//0.1
新聞熱點
疑難解答