精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

原生態Java 程序員容易忽視的編程細節

開發 后端
如果您熟悉C或C++,那么學習Java語言并不困難,這就像是會說瑞典語的人去學丹麥語一樣,雖然它們彼此互通,但是每種語言都有自己的語法標準。

Java是Java程序設計語言和Java平臺的總稱,要想學好一門語言,打好基礎最關鍵的,學習一種新的編程語言比學習新的口頭語言要容易得多。然而,在這兩種學習過程中,都要付出額外的努力去學習不帶口音地說新語言。

如果您熟悉C或C++,那么學習Java語言并不困難,這就像是會說瑞典語的人去學丹麥語一樣。語言雖有不同,但又彼此互通。但若不夠謹慎,您的口音每次都會暴露出您并非原生語言使用者這個秘密。

C++ 程序員往往會對Java代碼做出一些變形,而這樣的舉動將他們與原生Java語言用戶清晰地區分開來。他們的代碼可以無錯運行,但對于原生語言用戶來說,就是有一些地方不對勁。因而原生語言用戶可能會輕視非原生用戶。從 C 或 C++(或者 Basic、Fortran、Scheme 等)轉到Java語言時,您需要根除一些習慣用語,并糾正某些發音,以便流暢地使用新語言。在本文中,我探討了一些往往被忽視的Java編程細節,因為從語義上來說,它們并不重要,甚至是無關緊要的。它們純粹是風格和慣例問題。其中有些細節有著似是而非的理由,其他一些甚至連似是而非的理由也沒有。但所有這些細節都是當今編寫的Java代碼中真實存在的現象。

這是什么語言?

讓我們首先來看一段代碼,其作用是將華氏溫度轉換為攝氏度,如清單 1 所示:

清單 1. 一段C代碼?

  1. float F, C;   
  2. float min_tmp, max_tmp, x;   
  3. min_tmp = 0;    
  4. max_tmp = 300;   
  5. x  = 20;   
  6. F = min_tmp;   
  7. while (F <= max_tmp) {   
  8.    C = 5 * (F-32) / 9;   
  9.    printf("%f\t%f\n", F, C);   
  10.    FF = F + x;   
  11. }  

清單 1 中使用的是什么語言?很顯然是 C 語言 —請等一下,讓我們來看看完整的程序,如清單 2 所示:

清單 2. Java 程序

  1. class Test  {   
  2.  
  3.     public static void main(String argv[]) {    
  4.         float F, C;   
  5.         float min_tmp, max_tmp, x;   
  6.         
  7.         min_tmp = 0;    
  8.         max_tmp = 300;   
  9.         x  = 20;   
  10.         
  11.         F = min_tmp;   
  12.         while (F <= max_tmp) {   
  13.           C = 5 * (F-32) / 9;   
  14.           printf("%f\t%f\n", F, C);   
  15.           FF = F + x;   
  16.         }   
  17.     }   
  18.  
  19.     private static void printf(String format, Object... args) {   
  20.         System.out.printf(format, args);   
  21.     }   
  22.       
  23. }  

無論您是否相信,清單 1 和清單 2 都是使用 Java 語言編寫的。它們只是以 C 語言方言(老實說,清單 1 也確實可以是 C 代碼)編寫的 Java 代碼。這里的幾個習語標志著:編寫這段代碼的人是以 C 語言思考的,只是單純地將其翻譯為 Java 語言:

◆變量是 float 而非 double。
◆所有變量都是在方法上方聲明的。
◆初始化緊接聲明之后。
◆使用了 while 循環而非 for 循環。
◆使用了 printf 而非 println。
◆main() 方法的參數名為 argv。
◆數組括號緊接參數名之后,而非類型之后。

如果僅僅考慮所編寫的這些代碼是否能夠編譯或者是否會得到正確的結果,那么這些方言都不是錯誤的。如果分開來看,這幾點都并不明顯。但將它們結合在一起,就構成了一段非常古怪的代碼,Java 程序員難以讀懂,就像美國人難以聽懂北英格蘭人的方言一樣。您使用的此類 C 語言方言越少,您的代碼就會越清晰。請牢記這一點,下面我們將繼續分析 C 語言程序員暴露自己身份的一些常見方式,并說明如何才能使他們的代碼更符合 Java 程序員的眼光。

命名規范

根據您原本使用的是 C、C++ 還是 C#,您可能有一些較為主觀的類命名規范。舉例來說,在 C# 中,類名都是以小寫字母開頭的,方法名和字段名以大寫字母開頭。Java 風格則恰好相反。我沒有任何合理的原因能評判一種規范是否比另一種更好,但我了解,混用命名規范會使代碼看起來存在嚴重錯誤。這種做法也會導致 bug。如果您知道,每一個全部由大寫字母組成的名稱都是常量,則會以不同的方式進行處理。在尋找命名規范與聲明類型不匹配之處時,我發現了程序中的許多 bug。args而非 argv 這一點是最微不足道的,但也正是這場風格之爭所關注的細節。在Java的慣例中main()方法的參數名為args,而不是argv:

  1. public static void main(String[] args)  

這至多只是對 argv 這個名稱進行了一點細微的改進。作為參數的縮寫,它或多或少地比 argv 更易懂一些。 當然,在合乎慣例的 Java 代碼中,通常是禁止使用縮寫的(參見 請勿縮寫)。我們使用 args 作為 main() 方法的參數名的惟一原因與 C 程序員使用 argv 的原因是相同的 — ***本關于 C 語言的圖書的作者 Kernighan 和 Ritchie 使用了這個名稱。而 Gosling 和 Arnold 使用了 args。除此之外,再無其他原因。同樣,所有原生 Java 程序員都傾向于使用 args,如果您希望保持原汁原味,那么也應該這樣做。Java 編程中的基本命名規則非常簡單,也值得牢記:

◆類和接口名以大寫字母開頭,如 Frame。
◆方法、字段和本地變量名以小寫字母開頭,如 read()。
◆類、方法和字段名均使用駝峰式大小寫風格,如 InputStream 和 readFully()。
◆常量 — 終態靜態字段和臨時終態本地變量 — 全部適用大寫字母,并以下劃線分隔各詞,如 MAX_CONNECTIONS。

像 sprintf 和 nmtkns 這樣的名稱是超級計算機只有 32 KB 內存時代的遺物。編譯器將標識符限制為 8 個字符或更少,以此來節約內存。近 30 年來,這已經不再是需要擔心的問題。如今,再沒有任何理由不使用完整拼寫的變量和方法名稱。難以解讀、無元音字母的變量名清楚地表明這個程序出自一名皈依 Java 的 C 程序員之手,請參見清單 3:

清單 3. Abbrvtd nms r hrd 2 rd

  1. for (int i = 0; i < nr; i++) {   
  2.     for (int j = 0; j < nc; j++) {   
  3.         t[i][j] = s[i][j];   
  4.     }   
  5. }  

不縮寫、采用駝峰式大小寫風格的名稱更易讀易懂,如清單 4 所示:

清單 4. 未縮寫的名稱更易讀

  1. for (int row = 0; i < numRows; row++) {   
  2.     for (int column = 0; column < numColumns; column++) {   
  3.         target[row][column] = source[row][column];   
  4.     }   
  5. }  

一段代碼被閱讀的次數要遠遠超過編寫的次數,Java 語言為易讀性而進行了優化。C 程序員近乎沉迷于難解的代碼,而 Java 程序員則不然。Java 語言將易讀性置于簡潔性之前,有一些極為常用的縮寫形式,您仍然可以放心使用:

◆max 表示***(maximum)
◆min 表示最小(minimum)
◆in 表示 InputStream
◆out 表示 OutputStream
◆e 或 ex 表示 catch 子句中的異常(不用于其他位置)
◆num 表示數字(number),僅用作前綴,如 numTokens 或 numHits
◆tmp 表示主要在本地使用的臨時變量 — 針對實例,在交換兩個值的時候,除此之外(或許還有少數一些例外),您應完整拼寫出名稱中使用的所有詞。#p#

變量聲明、初始化和使用(重用)

早期版本的 C 需要在方法開始處聲明所有變量。這樣是為了在編譯器中實現一定的優化,允許它在 RAM 極為有限的環境中運行。因而,C 語言中的方法大多以幾行變量聲明開頭:

  1. int i, j, k;   
  2. double x, y, z;   
  3. float cf[], gh[], jk[];  

然而,這種風格也有一些缺陷。它將變量的聲明與其使用分離開來,使代碼的易讀性降低。此外,它會為多種不同的用途重用一個本地變量,有可能并非刻意而為。但若變量持有代碼的某個片段無法接受的殘值,這可能會帶來無法預料的 bug。這一點與 C 語言中簡短而難解的變量名結合在一起,將會后患無窮。

在 Java 語言(和較新版本的 C 語言)中,變量可在初次使用或接近初次使用時聲明。在編寫 Java 代碼時,請采取這種做法。這將使您的代碼更加安全、更不易出現 bug,也更易于閱讀。此外,Java 代碼通常在聲明變量時初始化各變量,而 C 程序員有時會寫出下面這樣的代碼:

  1. int i;   
  2. i = 7;  

盡管這在語法上是正確的,但 Java 程序員永遠不會寫出這樣的代碼。他們會這樣寫這段代碼:

  1. int i = 7;  

這有助于避免因意外使用了未經初始化的變量而導致的 bug。惟一的常見例外是一個變量的作用域需要同時包含 try 塊和 catch 或 finally 塊。這往往是由于代碼涉及需要在 finally 塊中關閉的輸入流和輸出流而導致的,如清單 5 所示:

清單 5. 異常處理可能會使變量的作用域難以合理設定

  1. InputStream in;   
  2. try {   
  3.   in = new FileInputStream("data.txt");   
  4.   // read from InputStream   
  5. }   
  6.  finally {   
  7.   if (in != null) {   
  8.     in.close();   
  9.   }   
  10. }  

但這幾乎是惟一的異常,這種風格的***一種連鎖反應就是 Java 程序員通常每行僅聲明一個變量。例如,他們初始化變量的方法如下:

  1. int i = 3;   
  2. int j = 8;   
  3. int k = 9;  

通常不會寫出下面這樣的代碼:

  1. int i=3j=8k=9;  

 這條語句在語法上是正確的,但除非在一種特殊的例外情況下,專業 Java 程序員是不會這樣做的,后文將介紹這種特殊情況。老式的 C 程序員甚至可能編寫一個四行的代碼:

  1. int i, j, k;   
  2. i = 3;   
  3. j = 8;   
  4. k = 9;  

Java 風格將聲明與初始化結合在一起,因而實際上要更簡練一些,只需要三行代碼。

將變量置入循環

常見的一種特殊情況就是在循環外部聲明變量。例如,考慮清單 6 中簡單的 for 循環,其作用是計算斐波那契數列的前 20 項:

清單 6. C 程序員喜歡在循環外部聲明變量

  1. int high = 1;   
  2. int low = 1;   
  3. int tmp;   
  4. int i;   
  5. for (i = 1; i < 20; i++) {   
  6.     System.out.println(high);   
  7.     tmp = high;   
  8.     highhigh = high+ low;   
  9.     low = tmp;   
  10. }  

所有這四個變量都是在循環外聲明的,盡管它們僅在循環內部使用,但作用域不止于此。這容易導致 bug,變量可能會在其目標作用域之外被重用。對于使用常用名的變量來說更是這樣,例如 i 和 tmp。某次使用的值可能會殘留下來,并以無法預計的方式干擾后續的代碼。***項改進(C 語言的現代版本也支持這項改進)是將 i 循環變量的聲明移到循環之內,如清單 7 所示:

清單 7. 將循環變量移入循環

  1. int high = 1;   
  2. int low = 1;   
  3. int tmp;   
  4. for (int i = 1; i < 20; i++) {   
  5.     System.out.println(high);   
  6.     tmp = high;   
  7.     highhigh = high+ low;   
  8.     low = tmp;   
  9. }  

到這里還沒有結束,經驗豐富的 Java 程序員還會將 tmp 變量移入循環,如清單 8 所示:

清單 8. 在循環內聲明臨時變量

  1. int high = 1;   
  2. int low = 1;   
  3. for (int i = 1; i < 20; i++) {   
  4.     System.out.println(high);   
  5.     int tmp = high;   
  6.     highhigh = high+ low;   
  7.     low = tmp;   
  8. }  

某些極度追求速度而又不夠老練的開發人員有時會提出反對意見,認為這種做法導致循環內執行過多操作,而不只是必要的操作,從而降低代碼運行速度。實際上,在運行時,聲明根本不會執行。將聲明移動到循環內絕不會給 Java 平臺造成負面的性能影響。許多程序員,包括許多經驗豐富的 Java 程序員都可能在這里止步。然而,還有一種不太常見的技巧,將所有變量都移入循環。您可以在 for 循環的初始化階段聲明多個變量,只需使用逗號分隔即可,如清單 9 所示:

清單 9. 在循環內聲明所有變量

  1. for (int i = 1high = 1low = 1; i < 20; i++) {   
  2.     System.out.println(high);   
  3.     int tmp = high;   
  4.     highhigh = high + low;   
  5.     low = tmp;   
  6. }   

這已經不僅僅是慣用的流暢代碼,而是真正的專業代碼。與 C 代碼相比,Java 代碼中的 for循環更多、while循環更少,原因就在于這種嚴格限制本地變量作用域的能力。 #p#

不要回收變量

上述討論得出這樣一個結論,Java 程序員幾乎不會為不同的值和對象重用本地變量。例如,清單 10 建立了一些按鈕及其關聯的動作偵聽器:

清單 10. 回收本地變量

  1. Button b = new Button("Play");   
  2.  b.addActionListener(new PlayAction());   
  3.  b = new Button("Pause");   
  4.  b.addActionListener(new PauseAction());   
  5.  b = new Button("Rewind");   
  6.  b.addActionListener(new RewindAction());   
  7.  b = new Button("FastForward");   
  8.  b.addActionListener(new FastForwardAction());   
  9.  b = new Button("Stop");   
  10.  b.addActionListener(new StopAction());  

經驗豐富的 Java 程序員會用 5 個不同的本地變量重寫這段代碼,如清單 11 所示:

清單 11. 未回收的變量

  1. Button play = new Button("Play");   
  2.  play.addActionListener(new PlayAction());   
  3.  Button pause = new Button("Pause");   
  4.  pause.addActionListener(new PauseAction());   
  5.  Button rewind = new Button("Rewind");   
  6.  rewind.addActionListener(new RewindAction());   
  7.  Button fastForward = new Button("FastForward");   
  8.  fastForward.addActionListener(new FastForwardAction());   
  9.  Button stop = new Button("Stop");   
  10.  stop.addActionListener(new StopAction());  

為多個邏輯上不同的值或對象重用一個本地變量容易導致 bug。實際上,本地變量(并非始終是它們指向的對象)并不影響內存和時間問題。所以不必為此擔憂,可以根據您的需要使用多個不同的本地變量。

信任垃圾收集器的內存管理能力出身 C++ 世界的程序員往往過度擔心內存消耗和內存泄漏問題。此類程序員有兩種表現。一種是在使用過變量后將變量設置為 null。另一種是調用 finalize()或將其用作一種偽析構函數。這是完全沒有必要的。盡管有些時候確實需要在 Java 代碼中手動釋放內存,但這種情況十分罕見。大多數時候,只需依靠垃圾收集器即可合理快速地完成內存管理。與大多數優化一樣,***實踐準則就是:除非能夠證明是有必要的,否則不要去干涉。

使用***原語數據類型

Java 語言有八種原語數據類型,但僅使用了其中的六種。在 Java 代碼中,float 比 C 代碼中少得多。float 變量或文字在 Java 代碼中極為罕見,更常用的是 double。使用 float 的惟一時機就是操縱精度有限的大型多維浮點數字數組,此時存儲空間較為重要。否則使用 double 即可。

比 float 更不常見的是 short。我在 Java 代碼中幾乎沒有見過 short 變量。只有惟一的一次(我要警告您,這是極其罕見的情況),讀入的外部定義數據格式碰巧包含 16 位有符號整型類型。在這種情況下,大多數程序員都會將其作為 int 讀入。

確定私有屬性的范圍

您是否見過清單 22 中這種 equals() 方法?

清單 12. C++ 程序員編寫的 equals()方法

  1. public class Foo {   
  2.  
  3.   private double x;   
  4.  
  5.   public double getX() {   
  6.     return this.x;   
  7.   }   
  8.  
  9.   public boolean equals(Object o) {   
  10.     if (o instanceof Foo) {   
  11.       Foo f = (Foo) o;   
  12.       return this.x == f.getX();   
  13.     }   
  14.     return false;   
  15.   }   
  16.  
  17.  }  

這個方法在技術上是正確的,但我確信,這個類是由一名保守的 C++ 程序員編寫的。他在一個方法中使用了私有字段 x 和公共 getter 方法 getX(),實際上是在一行代碼之中,這泄漏了他的身份。在 C++ 中,這種做法是必要的,因為私有屬性的范圍是對象而不是類。也就是說,在 C++ 中,同一個類的對象無法看到彼此的私有成員變量。他們必須使用 accessor 方法。在 Java 語言中,私有屬性的范圍是類而非對象。類型同為 Foo 的兩個對象可直接訪問對方的私有字段。

某些微妙 — 往往又不相關 — 的考慮思路認為,您應該在 Java 代碼中***直接字段訪問而非 getter 訪問,或者反之。字段訪問相對速度較快,但在少數時候,getter 訪問可能會提供與直接字段訪問略有不同的值,特別是在涉及子類的時候。在 Java 語言中,沒有任何理由在同一行代碼中為同一個類的同一個字段同時使用直接字段訪問和 getter 訪問。#p#

標點和語法方言

下面是一些與 C 語言對應部分不同的 Java 方言,在某些情況下,這樣的差異是為了利用某些 Java 語言特性。將數組括號緊接于類型之后,Java 語言聲明數組的方式與 C 語言中大致相同:

 

  1. int k[];   
  2. double temperature[];   
  3. String names[]; 

但Java語言也提供了一種替代性的語法,將數組復括號緊接于類型之后,而不是變量名之后:

  1. int[] k;   
  2.  double[] temperatures;   
  3.  String[] names; 

大多數 Java 程序員都采用了第二種風格。上面的代碼表示 k 的類型是 int 數組,temperatures 的類型是 double 數組,names 的類型是 String 數組。同樣,與其他本地變量一樣,Java 程序員習慣在聲明時初始化這些變量:

  1. int[] k = new int[10]; double[] temperatures = new double[75]; String[] names = new String[32];  

使用 s == null 而不是 null == s,謹慎的 C 程序員已經學會了將文字置于比較運算符的左側。例如:

 

  1. if (7 == x) doSomething(); 

目標在于避免意外地使用單等號賦值運算符而非雙等號比較運算符:

 

  1. if (7 = x) doSomething(); 

若將文字置于左側,這樣的錯誤就會成為編譯時錯誤。這項技巧是 C 語言中一項著名的編程實踐。它能幫助避免出現真正的 bug,因為若將文字置于右端,將始終返回 true。然而,不同于 C 語言,Java 語言具有獨立的 int 和 boolean 類型,賦值運算符返回 int,而比較運算符返回 boolean。因而,if (x = 7) 已經成為編譯時錯誤,就沒有必要為比較語句使用不自然的形式 if (7 == x),流暢的 Java 程序員不會這樣做。

連接字符串而非格式化字符串

多年以來,Java 語言一直沒有 printf() 函數。最終,Java 5 中增加了這個函數,有些時候能夠發揮作用。具體來說,在您希望將數字格式化為特定寬度或小數點后帶有特定位數的形式時,在這種不常見的情況下,格式字符串是一種便捷的字段特定語言。而 C 程序員往往在 Java 代碼中過多地使用 printf()。不應使用它取代簡單的字符串連接。例如:

 

  1. System.out.println("There were " + numErrors + " errors reported."); 

優于:

 

  1. System.out.printf("There were %d errors reported.\n", numErrors); 

變體使用了字符串連接,更易于閱讀,在簡單的情況下更是如此,此外,由于不存在格式字符串中的占位符和數字或變量參數的類型匹配不當的情況,出現 bug 的機會也更少。

***后增量而非前增量

在某些位置,i++ 和 ++i 之間的差別十分顯著。Java 程序員為這些位置定義了一個具體的名稱,那就是“bug”。不應該編寫依賴于前增量和后增量之間差異的代碼(對于 C 語言來說也是如此)。原因在于難以理解、易于出錯。如果您發現,在您編寫的代碼中兩者的差別有重大影響,那么就應該重新將代碼組織為獨立的語句,使之不再能夠影響大局。

如果前增量和后增量之間的差別不顯著 — 例如,for 循環的增量步數 — 80% 的 Java 程序員更傾向于使用后增量,只有 20% 的 Java 程序員會選擇前增量。i++ 比 ++i 更為常用。我無法評判孰是孰非,但事實就是這樣。如果您編寫的代碼中包含 ++i,那么任何閱讀您的代碼的人都要浪費時間去思考您為什么要這樣寫。因而,除非有特殊的原因必須使用前增量(應該不存在必須使用前增量的情況),否則請使用后增量。#p#

錯誤處理

錯誤處理是 Java 編程中最令人困惑的問題之一,也是真正地將語言風格大師與平凡開發者區分開來的一道門檻。實際上,僅僅錯誤處理就可以自成一篇文章。簡而言之,合理使用異常,切勿返回錯誤代碼。非原生語言使用者的***類錯誤是返回一個表示錯誤的值,而不是拋出異常。如果回溯到 Java 1.0 的年代,在 Sun 的所有程序員都充分理解了這種新語言之前,在某些 Java 語言自己的 API 中也會看到這樣的情況。例如,考慮 java.io.File 中的 delete()方法:

 

  1. public boolean delete() 

若文件或目錄被成功刪除,此方法將返回 true,否則返回 false。但最合理的做法 應該是,在成功完成時不返回任何內容,若存在出于某些原因未能刪除的文件,則拋出異常:

 

  1. public void delete() throws IOException 

在方法返回錯誤值時,每一個方法調用都要包含錯誤處理代碼。在大多數正常情況下,這使得跟蹤和理解方法的正常執行流變得困難。同時,如果由異常指出錯誤條件,錯誤處理即可單獨作為文件末尾處的一個代碼塊。如果存在更適合處理問題的位置,甚至可將其移動到其他方法和其他類中。這就帶來了錯誤處理中的第二種反模式。具有 C++ 背景的程序員有時會竭力在異常拋出后盡快處理異常。如果達到極限,可能會得到如清單 13 所示的代碼:

清單 13. 過早的異常處理

  1. public void readNumberFromFile(String name) {   
  2.     FileInputStream in;   
  3.     try {   
  4.         in = new FileInputStream(name);   
  5.     } catch (FileNotFoundException e) {   
  6.         System.err.println(e.getMessage());   
  7.         return;   
  8.     }   
  9.  
  10.     InputStreamReader reader;   
  11.     try {   
  12.         reader = new InputStreamReader(in, "UTF-8");   
  13.     } catch (UnsupportedEncodingException e) {   
  14.         System.err.println("This can't happen!");   
  15.         return;   
  16.     }   
  17.  
  18.  
  19.     BufferedReader buffer = new BufferedReader(reader);   
  20.     String line;   
  21.     try {   
  22.        line = buffer.readLine();   
  23.     } catch (IOException e) {   
  24.         System.err.println(e.getMessage());   
  25.         return;   
  26.     }   
  27.  
  28.     double x;   
  29.     try {   
  30.         x = Double.parseDouble(line);   
  31.     }   
  32.     catch (NumberFormatException e) {   
  33.         System.err.println(e.getMessage());   
  34.         return;   
  35.     }   
  36.  
  37.     System.out.println("Read: " + x);   
  38.  }  

這段代碼非常難以閱讀,甚至比異常處理取代的 if (errorCondition) 測試更為難解。流暢的 Java 代碼將錯誤處理與故障點分離開來,不會將錯誤處理代碼與正常執行流混合在一起。清單 14 中的版本更易于閱讀和理解:

清單 14. 保持代碼的主執行路線完好

  1. public void readNumberFromFile(String name) {   
  2.     try {   
  3.         FileInputStream in = new FileInputStream(name);   
  4.         InputStreamReader reader = new InputStreamReader(in, "UTF-8");   
  5.         BufferedReader buffer = new BufferedReader(reader);   
  6.         String line = buffer.readLine();   
  7.         double x = Double.parseDouble(line);   
  8.         System.out.println("Read: " + x);   
  9.     }   
  10.     catch (NumberFormatException e) {   
  11.         System.err.println("Data format error");   
  12.     }   
  13.     catch (IOException e) {   
  14.         System.err.println("Error reading from file: " + name);   
  15.     }   
  16.  }  

某些時候,您可能需要使用嵌套的 try-catch 塊來分離造成相同異常的不同故障模式,但這種情況并不常見。主要的實踐經驗是:如果一個方法中存在多個 try 塊,那么就表明方法過于龐大,應拆分為多個較小的方法。***,具有各種語言背景、剛剛接觸 Java 編程的程序員往往會錯誤地假設他們必須在拋出檢查異常(checked exception)的方法中捕捉到這些異常。而拋出異常的方法通常并不是應該負責捕捉異常的方法。例如,考慮如清單 15 所示的方法:

清單 15. 過早的異常處理

  1. public static void copy(InputStream in, OutputStream out) {   
  2.   try {   
  3.     while (true) {   
  4.       int datum = in.read();   
  5.       if (datum == -1) break;   
  6.       out.write(datum);   
  7.     }   
  8.     out.flush();   
  9.   } catch (IOException ex) {   
  10.      System.err.println(ex.getMessage());   
  11.   }   
  12.  }  

此方法沒有足夠的信息來處理很有可能發生的 IOException。它并不了解誰調用了它,也不了解故障的后果。對于此方法來說,惟一合理的舉措就是允許 IOException 上行至調用方。編寫此方法的正確方式如清單 16 所示:

清單 16. 并非所有異常都需要在***時間捕捉

  1. public static void copy(InputStream in, OutputStream out) throws IOException {   
  2.   while (true) {   
  3.     int datum = in.read();   
  4.     if (datum == -1) break;   
  5.     out.write(datum);   
  6.   }   
  7.   out.flush();   
  8.  }  

簡而言之,這更為簡單、更容易理解,將錯誤信息傳遞給代碼中最適合處理這些信息的部分。這些問題是否真的那么重要?這些問題都不是關鍵問題。某些是慣例:在初次使用時聲明;在不知道如何處理錯誤時拋出異常。其他則是純粹的風格慣例(args 而非 argv;i++ 而非 ++i)。我并不認為這些規則能使您的代碼運行速度更快,但其中一些確實能幫助您避免 bug。如果您要成為一名流暢的 Java 語言使用者,所有這些規則都是重要的。

無論如何,以純正的口音講話(或編寫代碼)都能使其他人更加尊重您、更加關注您所表達的內容,甚至會為您表達的內容付給您更多的錢。此外,以純正的口音使用 Java 語言要比說無口音的法語、漢語或英語要簡單得多。一旦您學會了一門語言,就值得付出努力來使您的表達變得更加原汁原味。

【編輯推薦】

  1. 通過Java泛型實現數組排序和搜索的通用方法
  2. Maven是什么?回顧Java社區的變革
  3. Java元數據總結:Java注釋的使用和定義
  4. XML和Java Bean的互相轉換攻略
  5. Java堆棧溢出的機制與原理

 

責任編輯:王曉東 來源: IBM
相關推薦

2014-02-09 14:34:56

2017-02-08 09:51:27

JavaScript細節

2013-03-28 15:24:29

程序員

2011-11-08 09:21:16

虛擬化云計算VDI

2016-03-28 14:44:02

DockerMacwindows

2012-12-25 17:40:33

2012-06-15 09:54:58

程序員編程開發

2018-09-29 16:10:02

編程語言Java程序員

2009-11-23 15:22:16

2015-08-20 14:34:25

程序員java基礎網絡編程

2012-08-30 10:05:40

編程編程語言程序員

2013-11-14 10:05:25

程序員職業轉型

2015-02-03 02:40:33

程序員盲人程序員

2014-11-10 09:46:57

程序員

2016-01-11 11:32:41

Java程序員錯誤

2015-10-15 09:38:21

程序員發福

2020-07-27 08:34:17

程序員技術設計

2018-08-30 11:11:32

前端程序員基礎知識

2021-10-26 16:25:25

編程語言JavaPython

2013-08-20 09:33:59

程序員
點贊
收藏

51CTO技術棧公眾號

粉嫩嫩av羞羞动漫久久久| 一道在线中文一区二区三区| 亚洲伦在线观看| 国产二区不卡| 亚洲无码精品一区二区三区| 先锋资源久久| 亚洲精品国产精品自产a区红杏吧| 日日碰狠狠丁香久燥| 成人影院在线看| 91丨porny丨国产| 91在线观看免费高清| 亚洲高清毛片一区二区| 久久久久久美女精品 | 美女扒开腿让男人桶爽久久动漫| 色综合久久66| 青青草综合在线| 大片免费播放在线视频| 成人h动漫精品一区二区| 国产精品美女主播| 国产又大又黄又粗| 国产精品sm| 色先锋资源久久综合5566| jjzz黄色片| 亚洲网站三级| 91福利在线观看| 日韩免费视频播放| 性欧美videoshd高清| 亚洲国产高清aⅴ视频| 久久精品国产一区二区三区不卡| 朝桐光av在线一区二区三区| 免费高清在线视频一区·| 日本精品久久久| 国产稀缺真实呦乱在线| 欧美91大片| 日韩亚洲国产中文字幕| 久久精品视频18| 麻豆国产欧美一区二区三区r| 欧美一区国产二区| 青青草久久伊人| 草民电影神马电影一区二区| 日韩欧美国产高清91| 亚洲 自拍 另类小说综合图区 | 欧美激情一区二区三区成人| av在线播放中文字幕| 精品久久成人| 亚洲色图偷窥自拍| 9.1成人看片免费版| 欧美色图五月天| 日韩激情视频在线| www.久久国产| 国产调教一区二区三区| 亚洲午夜色婷婷在线| 成人午夜福利一区二区| 最近国产精品视频| 亚洲欧美在线一区二区| 精品无码人妻一区| 精品久久91| 中文字幕日韩欧美| 男女全黄做爰文章| 偷偷www综合久久久久久久| 久久精品国产亚洲| www.av视频| 亚洲美女一区| 青青草原一区二区| 超碰在线观看91| 免费成人在线网站| 亚洲已满18点击进入在线看片| 97在线视频人妻无码| 国模大尺度一区二区三区| 亚洲va国产va天堂va久久| 精品人妻一区二区三区换脸明星| 国产超碰在线一区| 精品午夜一区二区三区| 国产片在线观看| 国产精品免费看片| 久久最新免费视频| 伊人成综合网站| 欧美四级电影网| 天天综合成人网| 成人动漫视频| 亚洲色图狂野欧美| 国产午夜精品理论片在线| 欧美日本不卡高清| 欧美在线一级va免费观看| 伊人免费在线观看| 成人av综合在线| 日本一区二区三区免费看| 黄色网址在线免费观看| 香蕉乱码成人久久天堂爱免费| 黄色片视频在线播放| 国产精品日韩精品在线播放| 亚洲精品99999| 手机免费观看av| 激情综合网址| 国产美女精品视频免费观看| 亚洲精品97久久中文字幕无码| 久久蜜桃一区二区| 日本三级中文字幕在线观看| 中文字幕在线直播| 欧美一区二区视频免费观看| 国产吞精囗交久久久| 久久久国产精品| 欧美亚洲另类激情另类| 国产精品一区二区三区在线免费观看 | 亚洲三级电影网站| 男人透女人免费视频| 亚洲精品午夜| 日韩在线免费视频| www亚洲视频| 国产高清不卡二三区| 色综合影院在线观看| 波多野结衣中文在线| 欧美日韩你懂得| 青青草视频成人| 黄色av日韩| 成人性生交xxxxx网站| 免费一级毛片在线观看| 亚洲一级二级在线| 日韩av片免费观看| 经典一区二区| 亚州欧美日韩中文视频| av男人天堂网| 亚洲欧洲精品一区二区三区| 国产成人精品视频ⅴa片软件竹菊| 大奶一区二区三区| 欧美理论电影在线播放| 在线观看国产黄| 国产欧美视频在线观看| 国模吧无码一区二区三区| 91大神精品| 欧美成人高清视频| 国产精品熟女久久久久久| 国产喷白浆一区二区三区| 女人天堂av手机在线| 国产精品主播在线观看| 欧美激情免费在线| 精品久久国产视频| 亚洲私人黄色宅男| 99中文字幕在线| 国产精品久久观看| 国产在线播放91| 午夜看片在线免费| 欧美日本视频在线| 国产老头老太做爰视频| 久久精品国产99久久6| 亚洲一区二区三区四区中文| 成人四虎影院| 日韩一区视频在线| 国产又大又黑又粗| 国产精品成人一区二区艾草 | 欧美s码亚洲码精品m码| 精品成人自拍视频| 57pao国产成人免费| 午夜视频在线免费播放| 精品久久久久久久久中文字幕| 中文字幕 日本| 先锋影音久久| 日韩av图片| 欧美综合影院| 欧美成人精品xxx| 亚洲国产精品成人久久蜜臀| 午夜视频一区在线观看| 疯狂揉花蒂控制高潮h| 久久人人97超碰国产公开结果| 日本一区二区三区免费看 | 97夜夜澡人人双人人人喊| 日本在线视频www鲁啊鲁| 欧美va亚洲va| 99精品在线播放| 国产精品丝袜91| 久久精品视频在线观看免费| 亚洲午夜伦理| 秋霞久久久久久一区二区| 777午夜精品电影免费看| 久久精品99久久久香蕉| 成人午夜免费福利| 欧美性xxxx在线播放| 国产一二三四区在线| 精品亚洲免费视频| 免费看又黄又无码的网站| 欧美一级本道电影免费专区| 91免费的视频在线播放| 国产在线88av| 最近2019年好看中文字幕视频| 国产精品乱码久久久| 午夜精品在线视频一区| 国产黄色大片免费看| 国产激情一区二区三区桃花岛亚洲| a级黄色小视频| 欧美视频免费| 鬼打鬼之黄金道士1992林正英| 亚洲美女久久精品| 美女性感视频久久久| 黄色av免费在线观看| 日韩亚洲欧美综合| 欧美高清69hd| 五月婷婷激情综合| 国产三级aaa| www一区二区| 欧美体内she精高潮| 三级影片在线观看欧美日韩一区二区 | 国产精品亚洲网站| 黄视频网站在线观看| 最近2019中文字幕第三页视频| 亚洲精品一区二区口爆| 欧美日韩在线亚洲一区蜜芽| 日韩大片免费在线观看| 最新成人av在线| 在线小视频你懂的| 91丝袜国产在线播放| 一级 黄 色 片一| 日韩av网站在线观看| 2018国产在线| 国产精品大片| gogogo免费高清日本写真| 国产欧美一区二区三区精品观看| 亚洲一区二区三区在线免费观看| 欧美大片1688网站| 欧美一区二区影院| 国产精品—色呦呦| 欧美成年人视频网站欧美| 日本天堂在线观看| 在线观看国产精品淫| 九色在线播放| 精品丝袜一区二区三区| 亚洲黄色在线观看视频| 欧美一卡二卡在线| 国产又色又爽又黄又免费| 欧美午夜一区二区| 一级片免费在线播放| 欧美日韩在线视频一区二区| 国产成人在线观看网站| 亚洲午夜久久久久久久久电影网 | 加勒比一区二区| av日韩在线网站| 国产精品久久久久久亚洲色| 国产乱理伦片在线观看夜一区| 久久久精品高清| 久久精品国产99国产| www.国产视频.com| 精油按摩中文字幕久久| 色播五月激情五月| 精品午夜一区二区三区在线观看| 依人在线免费视频| 卡一卡二国产精品| 91热视频在线观看| 国产成人三级在线观看| 69久久精品无码一区二区| 国产裸体歌舞团一区二区| 午夜福利123| 国产精品资源网站| 女性生殖扒开酷刑vk| 成人精品国产一区二区4080| 少妇一级淫片免费放播放| 成人不卡免费av| 免费看黄色aaaaaa 片| 久久精品人人爽人人爽| 呻吟揉丰满对白91乃国产区| 一区在线播放视频| 国产va在线播放| 亚洲成人第一页| 亚洲黄网在线观看| 欧美久久免费观看| 亚洲AV无码精品色毛片浪潮| 亚洲国产精品va在线看黑人动漫| 天天av综合网| 色妞久久福利网| 亚洲精品白浆| 国产91对白在线播放| 99精品国自产在线| 91情侣在线视频| 色狼人综合干| 亚洲欧美日产图| 欧美日韩99| 日日摸日日碰夜夜爽av| 麻豆精品一区二区综合av| 丰满饥渴老女人hd| 久久久久久久精| 欧美手机在线观看| 欧美日韩亚洲一区二| 亚洲图片中文字幕| 精品国产乱码久久久久久1区2区| 国内三级在线观看| 久久99久久99精品免观看粉嫩| 国内激情视频在线观看| 国产日韩精品一区二区| 动漫av一区| 一本一本a久久| 亚洲精品日韩久久| 国产乱女淫av麻豆国产| www.色精品| 黄色香蕉视频在线观看| 欧美日韩中文在线| 国产乱码精品一区二区| 亚洲美女av黄| av网站导航在线观看免费| 欧美自拍视频在线观看| 久久久国产精品入口麻豆| 欧美日韩一区在线视频| 国产尤物精品| 午夜一区二区视频| 国产亲近乱来精品视频| 日韩网红少妇无码视频香港| 欧美日韩久久一区| 日本五码在线| 久久人91精品久久久久久不卡 | 国产精品乱码一区二区三区| 精品国产视频| 国产精品333| 国产成人精品一区二区三区四区 | 天天综合网网欲色| 情侣黄网站免费看| 成人午夜激情片| 一区二区国产精品精华液| 日本精品一区二区三区高清 | 欧美1区二区| 米仓穗香在线观看| 久久成人免费网站| 欧美黄色一级生活片| 欧美日韩在线视频一区二区| 亚洲精品久久久久久无码色欲四季 | 国产xxxxxxxxx| 有码一区二区三区| 91久久国语露脸精品国产高跟| 国产视频在线一区二区| 91桃色在线| 国产精品久久久久久久天堂第1集 国产精品久久久久久久免费大片 国产精品久久久久久久久婷婷 | 亚洲男人的天堂av| 中文字幕精品一区二| 亚洲视频网站在线观看| 成人性生活av| 蜜桃免费一区二区三区| 国产精品久久国产愉拍| 亚洲の无码国产の无码步美| 亚洲综合免费观看高清在线观看| 国产日本精品视频| 久久精品国亚洲| 成人午夜888| 色乱码一区二区三区熟女| 精品亚洲欧美一区| 精品欧美一区二区久久久久| 欧美一区二区三区日韩视频| 搞黄网站在线观看| 91免费观看| 1024精品一区二区三区| 艳妇乳肉豪妇荡乳xxx| 午夜精品福利在线| 视频在线不卡| 555www成人网| 国产传媒欧美日韩成人精品大片| 成年人小视频网站| 中文在线资源观看网站视频免费不卡| 一级特黄免费视频| 久久视频免费在线播放| 久久久久久爱| 奇米精品一区二区三区| 久久久国产精华| 亚洲一卡二卡在线| 欧美成人免费视频| 激情亚洲另类图片区小说区| 国产精品亚洲a| 中文字幕一区日韩精品欧美| www.com在线观看| 性色av香蕉一区二区| 伊人久久大香线蕉综合网站| 男女无套免费视频网站动漫| 成人欧美一区二区三区在线播放| 国产成人精品免费看视频| 欧美劲爆第一页| 夜夜春成人影院| 欧美日韩精品区别| 婷婷亚洲久悠悠色悠在线播放| 国产免费永久在线观看| 91久久中文字幕| 99在线精品免费视频九九视 | 国产精品视频色| 欧美精品福利| 日韩网站在线播放| 欧美精选午夜久久久乱码6080| 黄污视频在线观看| 欧美1o一11sex性hdhd| 国产一区二区三区在线观看免费 | 亚洲国产123| 亚洲精品美女免费| 欧美爱爱视频| 国产午夜大地久久| 国产精品盗摄一区二区三区| 可以免费观看的毛片| 国产精品日韩在线观看| 欧美三区美女| 少妇视频在线播放| 亚洲精品国产精品国产自| 在线成人免费| 成人一级片网站| 亚洲激情第一区| 最新国产在线观看| 精品国产乱码久久久久久丨区2区 精品国产乱码久久久久久蜜柚 | 午夜精品一区二区三区在线播放| 欧美熟乱15p| 在线观看国产三级|