級別:初級EricE.Allen,軟件工程師,Cycorp,Inc2001年2月19日歡迎光臨診斷Java代碼,一個隔周更新的新專欄,它的內容集中在Java解決方案上,旨在讓您能夠順利進行日常編程工作。本文為第一篇,介紹了錯誤模式的概念,一個非常有用的概念,它將提高您檢測和修正代碼中錯誤的能力。您會了解到一種最普遍的錯誤模" />

日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

高質量JAVA:錯誤模式

系統 2412 0

錯誤模式:介紹

診斷和糾正 Java 程序中反復出現的錯誤類型

文檔選項
將打印機的版面設置成橫向打印模式

打印本頁

將此頁作為電子郵件發送

將此頁作為電子郵件發送

<!----><!----><!---->

級別: 初級

Eric E. Allen , 軟件工程師, Cycorp, Inc

2001 年 2 月 19 日

歡迎光臨診斷 Java 代碼,一個隔周更新的新專欄,它的內容集中在 Java 解決方案上,旨在讓您能夠順利進行日常編程工作。本文為第一篇,介紹了錯誤模式的概念,一個非常有用的概念,它將提高您檢測和修正代碼中錯誤的能力。您會了解到一種最普遍的錯誤模式,這將為您開始識別和避免更高級的錯誤模式奠定基礎。
<!----><!----><!---->

錯誤模式和它們為什么有用

正如好的編程技能涉及很多設計模式(您可以在不同的程序上下文中組合和應用這些模式)的知識一樣,好的調試技能也涉及對 錯誤模式 的一定了解。錯誤模式就是已發出的錯誤和程序中潛在的錯誤之間的重復出現的相互關系。這種概念對編程來說并不新鮮。醫生們在診斷疾病時依靠相似類型的相互關系。他們在實習期間通過和資格較老的醫生共同工作來學習這些。他們的教育就是集中在做這種診斷上的。相反,我們軟件工程師的教育是集中在過程設計和算法分析上的。這些技能固然重要,但是人們對調試過程的教育卻很少關注。相反,我們得自己去“拾起”這種技能。隨著極端編程的出現和它對單元測試的注重,這種做法已經開始改變了。但是頻繁的單元測試只是解決了問題的一部分。一旦發現錯誤,就必須診斷和糾正它們。幸運的是,很多錯誤都遵循我們可以識別的幾種錯誤模式的其中一種。一旦您可以識別出這些錯誤模式,您就可以診斷出錯誤的原因并且更快地糾正它了。

錯誤模式與反模式有關,反模式是一次又一次被證明是失敗的公共軟件設計的模式。雖然反模式是設計模式,錯誤模式卻是與編程錯誤相關的錯誤的程序行為的模式。這與設計根本沒有關系,而是與編程和調試過程有關。





回頁首


通過示例學習

為了說明錯誤模式后面的思想,讓我們來考慮一種基本錯誤模式,編程新手(經常還有更高級的程序員)常常會遇到這種錯誤模式。在后面的文章中,我們會談到更高級的錯誤模式。對每一種模式,我會討論將有助于把該模式的錯誤的發生控制到最少的編程原則(并非暗示所有的錯誤都是不遵循編程原則的結果;不管我們遵循多少原則,我們都會犯錯誤)。

為了分類起見,我會使用下面的形式(從醫學上借用一些術語)來概括錯誤模式描述:

  • 模式名稱
  • 癥狀
  • 起因
  • 治療方法和預防措施

Rogue Tile 模式

也許它是編程新手中最普遍的錯誤模式,起因是復制和粘貼一段代碼到程序的其它部分。有時,復制的一小部分因為功能上需求的略微不同而作了改動。不可避免地,錯誤在一個副本中被修正了,而在另一個副本中沒有被修正,這樣在錯誤癥狀復發時就會讓您很頭疼。盡管大多數程序員很快就熟悉了這種錯誤模式,但他們中很少人采取適當的措施來將這種錯誤的出現控制到最少。您很容易就會偷懶不去思考而簡單地復制您認為已經可以運行的代碼。但是工作效率由于修正代碼而喪失,這是因為不加選擇的復制―粘貼操作很快降低了復制代碼帶來的任何工作效率。

我稱此為 Rogue Tile 模式是因為,一段代碼的各個副本可以被看成是分布在程序中的“tile”。由于不同副本中的代碼出現了差異,副本就變成了“rogue tile”。

癥狀

這種錯誤的模式的最普遍癥狀是,在您認為已經修正了問題以后,程序還繼續表現出錯誤的行為。

起因

為了理解這種情況發生的原因,我們來看看下面的二元樹類層次結構:

                    public abstract class Tree {
}
public class Leaf extends Tree {
 public Object value;
 ...
}
public class Branch extends Tree {
 public Object value;
 public Tree left;
 public Tree right;
 ...
}

                  


對于這些類要注意的第一件事就是,兩種具體類都包含 Object 類型的 value 字段。如果您決定稍后讓樹包含,比如說, Interger ,您也許會忘記更新其中的一個字段聲明。如果程序的其它部分需要這些字段是 Interger 的話,程序就很可能不會編譯。您或許記得您改變了其中一個類的 value 字段的類型,卻忽略了一個事實,就是您沒有在其它類中作相應的改變。

一些預防措施

當然,這個示例所示的錯誤是編程新手可以很快學會通過分解出公共代碼來避免的。在本例中,字段聲明應該移到 Tree 類中。它的兩個子類就會繼承這個字段,而且對字段聲明的任何改變都只需要在一個地方出現。

繼續看這個示例,我們可能還會編寫在一個 Tree 中相加和相乘所有節點的方法。為了簡單起見,我將以遞歸的方式來編寫這些方法。

                    // in class Tree:
 public abstract int add();
 public abstract int multiply();
 // in class Branch:
 public int add() {
  return this.value.intValue() + left.add() + right.add();
 }
 public int multiply() {
  return this.value.intValue() * left.multiply() + right.multiply();
 }
 // in class Leaf:
 public int add() { return this.value.intValue(); }
 public int multiply() { return this.value.intValue(); }

                  

請注意我在 multiply 方法中為 Branch 類引入的錯誤:我沒有用第三項去乘,而是加了它。錯誤發生了,因為我通過復制 add 方法中的代碼并作輕微(但不完全)的改動創建了 multiply 方法。這種錯誤非常隱蔽,因為調用 multiply 方法永遠不會發出錯誤信號。事實上,在很多情況下,它會返回一個看上去完全合理的結果。

就象以前一樣,我們可以通過分解出公共代碼來將這種錯誤控制到最少。在這種情況下,我們可以編寫一個單獨的方法,它在 Tree 上累計一個運算符(作為一個參數傳送)。我們可以使用一種被稱為公共模式的設計模式(不是錯誤模式?。┰趯ο笾蟹庋b這個運算符。

                    public abstract class Operator {
 public abstract int apply(int l, int r);
}
public class Adder extends Operator {
 public int apply(int l, int r) {
   return l + r;
 }
}
public class Multiplier extends Operator {
 public int apply(int l, int r) {
   return l * r;
 }
}

                  

然后我們就可以如下面的代碼所示在我們的 Tree 類層次結構中改變這個方法:

                    // in class Tree:
 public abstract int accumulate(Operator o);
 public int add() {
   return this.accumulate(new Adder());
 }
 public int multiply() {
   return this.accumulate(new Multiplier());
 }
 // in  class Leaf:
 public int accumulate(Operator o) {
   return value.intValue();
 }
in class Branch: 
 public int accumulate(Operator o) {
   return o.apply(this.value.intValue(),
                  o.apply(left.accumulate(o),
                         right.accumulate(o)));
 }

                  

通過分解出公共代碼,我們消除了在 add multiply 方法正文中出現復制―粘貼錯誤的可能性。另外,請注意我們不再需要為 Tree 的每一個子類編寫單獨的 add multiply 方法了。

分解出公共代碼是一個很好的習慣,但它并不適用于所有的情況。比如說,Java 類型系統的簡單性經常迫使我們在精確類型檢驗和保持對程序的每個不同的功能性元素的單點控制(請參閱 參考資料 ,閱讀我寫的關于 NextGen 的文章)之間作出選擇。正因為這個,Rogue Tile 模式是所有開發人員必須一直努力以控制到最少的一種錯誤類型。





回頁首


下一篇內容是什么?

簡而言之,這是我們的第一個錯誤模式。您可能想把它剪下來釘在您的公告牌上作為提醒。

  • 模式:Rogue Tile
  • 癥狀:代碼好像表現出前面糾正過的錯誤依然存在。
  • 起因:復制―粘貼代碼片段的至少一個副本還包含在其它副本中已經修正了的錯誤。
  • 治療和預防措施:如果可能,分解出公共代碼;否則就對其進行更新。避免復制和粘貼代碼。

在我的下一篇文章中,我會探究 Java 代碼中出現過的其它一些普遍的錯誤模式。我們將特別看一下作為空指針異常而出現的錯誤模式,并討論如何將它們的出現次數控制到最少。



參考資料

  • 您可以參閱本文在 developerWorks 全球站點上的 英文原文 .

  • 訪問 模式主頁 ,這是一個介紹設計模式以及如何使用它們的優秀主頁。

  • 反模式主頁 提供了關于該主題的書籍的信息和鏈接。

  • 如果您還沒有這么做,請查閱 極端編程 ,一個快速開發簡潔的、健壯的軟件的強大的新方法。

  • 然后下載 JUnit 并立刻開始單元測試。

  • Eric Allen 的關于 NextGen (Java 的一個運行時泛型類型的擴展)的文章說明了一個更加強大的類型系統是怎樣幫助減輕存在于分解公共代碼和使用類型系統在編譯期間捕捉錯誤的兩個目標之間的一些壓力的。


關于作者

?

Eric Allen 在 Cornell 大學獲得計算機科學和數學的學士學位。他目前是 Cycorp 公司的 Java 軟件開發人員帶頭人,還是 Rice 大學的編程語言小組的半工半讀碩士生。他的研究涉及正規語義模型和 Java 語言的擴展,都是在源代碼和字節碼的級別上的。目前,他正在為 NextGen 編程語言實現一種從源代碼到字節碼的編譯器,這也是 Java 語言的泛型運行時類型的一種擴展。

高質量JAVA:錯誤模式


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 阿拉善左旗| 吉林省| 苍梧县| 高安市| 南川市| 三都| 凤凰县| 陈巴尔虎旗| 丰顺县| 洛隆县| 黑水县| 井冈山市| 玉山县| 九龙城区| 马公市| 巴青县| 肇东市| 鄂伦春自治旗| 米泉市| 钟祥市| 屏边| 泉州市| 洛浦县| 松阳县| 商南县| 霍山县| 宾川县| 铁力市| 百色市| 彩票| 大庆市| 新绛县| 邵阳市| 克拉玛依市| 洛阳市| 津市市| 突泉县| 娄烦县| 荣昌县| 铁力市| 会理县|