發現問題

單元測試

 

一個簡單的測試框架

 

 

Junit

 

斷言語法 (這個以後用到再好學習)
既然我們可以使用其它的編程結構來仿真斷言的效用,這表明將斷言添加到 Java 的關鍵之
處在於它們很容易編寫。斷言語句有兩種常用的形式:
 
assert boolean-expression;
assert boolean-expression: information-expression;

 

 

用 Ant構建

 

自動化所有事物

 

用 CVS進行版本控制

 

執行每日構建(daily build)

 

記錄日誌級別

 

日誌記錄

LogRecord是一個信使(Messenger)對象 ,它的任務僅僅是將信息從一個地方傳送到
另一個地方。LogRecord中的所有方法都是獲取器(getter)和設置器(setter),下
面這個例子使用獲取器方法卸出了所有存儲在LogRecord中的信息。

 

 

多重處理器

 

過濾器
當我們要編寫代碼將日誌記錄消息發送給 Logger 對象時,那麼就在編寫代碼的時候,我
們通常就要決定日誌記錄消息應該是什麼級別(日誌記錄 API 當然允許我們設計更復雜的
系統,在其中消息級別可以動態決定,但是在實際中並不普遍)。Logger 對象有一個可以
設置的級別,以便能夠決定它可以接收什麼級別的消息;而其它所有消息都將被忽略掉。這
可以被看作是一種基本的過濾功能,但是通常這也就是我們所需要的全部了。

 

格式器(Formatter)
Formatter 是一種向 Handler 的處理步驟中插入格式化操作的方式。如果我們一個
Handler 註冊了一個 Formatter 對象。那麼在通過 Handler 發佈 LogRecord 之前,它
首先會被送到 Formatter。在被格式化之後,LogRecord 被返回給 Handler,接着把它
發佈出去。
 

通過名字空間控制記錄日誌級別
儘管不是強制的,但是將要使用日誌記錄器的類名傳遞給記錄器是明智的。這使得我們可以
操縱在相同的包層次中(按包目錄結構的粒度)的日誌記錄器組的記錄日誌級別。例如,我
們可以修改在 com 中的所有包的所有記錄日誌級別,或者僅在 com.bruceeckel 中,更
或者僅在 com.bruceeckel.util 中的所有包的所有記錄日誌級別,如隨後的例子所示:

 

大型工程的記錄日誌實踐
乍一看,Java 記錄日誌 API 對大多數編程問題來說,可能都顯得過於工程化了。直到我們
開始創建更大的工程時,這些額外的特性和性能才能派上用場。在這一節我們將會着眼於這
些特性以及推薦的使用它們的方法。如果我們僅在較小的工程上使用日誌記錄,那麼我們可
能不需要用到這些特性。
 
配置文件

 

 
調試
儘管恰當使用System.out語句或者日誌記錄信息可以產生對程序行爲非常有價值的洞察
16
,但對於困難問題這種方法就變得笨拙而費時了。另外,我們可能需要比允許打印語句要
更深入地洞察程序。正因爲如此,我們需要調試器。
 
除了可以更快更容易地顯示用打印語句產生的信息,調試器還可以設置斷點
(breakpoint),然後當程序到達這些斷點時會停止運行。調試器還可以顯示任何時刻的
程序狀態,查看我們感興趣的變量值,逐行地運行程序,連接在遠程運行的程序,以及其它
更多的功能。尤其當我們開始創建較大的系統時(在這裏 bug 可能更容易被隱藏起來),去
熟悉調試器是很值得的。

 

使用 JDB 調試
 
Java 調試器(JDB, Java Debugger)是一個裝載在 JDK 中的命令行調試器。根據 JDB

的調試指令以及它的命令行界面,JDB 至少從概念上講是 Gnu 調試器(Gnu Debug,GDB,
是從最初的 Unix DB 中得到啓發的)的後代。JDB 對於學習如何進行調試和執行較簡單的
調試任務來說很有用,而且有助於你去了解無論 JDK 安裝在哪裏 JDB 總是可用的。不過,
對於較大的工程,我們可能希望能夠使用一個圖形化調試器,這在稍後會講述。 
 

形化調試器
使用像 JDB 這樣的命令行調試器很不方便。我們必須要使用顯式命令進行查看變量值的狀
態(局部變量,轉存變量),列出源代碼執行位置(列表),找出系統中的線程(線程),設
置斷點(斷入方法內部,斷在方法外部),等等諸如此類的操作。圖形化的調試器使得我們
不需要顯式命令,通過使用幾下點擊就能完成這些事情,而且還可以查看正在被調試的程序
細節。
 
因此,儘管我們可能想嘗試使用 JDB 開始進行調試,不過我們會發現學習使用圖形化調試
器來快速跟蹤到 bug 顯得更有效率。在本書此版本的編寫過程中,我們開始使用 IBM 的
Eclipse 編輯器和開發環境,它包含一個很好的 Java 圖形化調試器。Eclipse 的設計與
實現都很優良,而且我們可以從 www.Eclipse.org 免費下載它(這是一個免費的工具,
不是實驗版或共享軟件——感謝 IBM 投入資金、時間和努力使它可以供每個人使用)。
 
其他的免費開發工具也有圖形化的調試器,例如 Sun 的 Netbeans 和 Borland 的
JBuilder 免費版。

追蹤內存消費
下面是剖析器爲說明內存使用目的而能夠展示的數據類型:
   爲某一特定類型分配的對象個數。   對象分配發生的地方。   在該類實例的分配中涉及到的方法。   閒散對象:已分配的,但是沒有被使用過的,也沒有被垃圾回收的對象。這些對象
會持續增加 JVM 堆的大小而且會表現爲內存泄漏,這可能會引起內存溢出的錯誤
或者在垃圾回收器方面過多的開銷。   過度分配的臨時對象,它們增加了垃圾收集器的工作量,因此降低了應用的性能。   在釋放那些添加到垃圾收集器但是沒有被移除掉的實例時所導致的失敗(這是閒散
對象的特殊情況)。
 

追蹤 CPU 的使用
剖析器還能追蹤到 CPU 在代碼的不同部分花費了多少時間。它們能告訴我們:
   方法被調用的次數。   每個方法佔用 CPU 時間的百分比。如果某個方法調用了其他的方法,那麼剖析器
可以告訴我們花費到這些其他方法上的時間總量。   每個方法花費的絕對時間,包括它等待 I/O 的時間,加鎖時間等。這些時間依賴
於系統的可用資源。
 
這樣我們就能夠確定代碼的那些部分需要優化了。

 

覆蓋測試
覆蓋測試(coverage testing)可以顯示在測試期間沒有被執行的代碼行。這樣就會吸
引我們注意那些沒有被使用到的代碼,因此它們應該成爲被移除或重構的候選對象。
 

JVM剖析接口
剖析代理(profiler agent)對那些它感興趣的事件與 JVM 進行通信。Java 虛擬機的
剖析接口支持以下事件:
   進入和退出方法   分配、移動和釋放一個對象   創建和刪除一個堆區域   開始和結束一次垃圾收集循環   分配和釋放一個 JNI 全局引用   分配和釋放一個 JNI 弱全局引用   載入和卸載某個編譯過的方法   開始和結束某個線程   爲設備準備的類文件數據   載入和卸載某個類文件   處於競爭狀態的 Java 監視器的事件:等待進入,進入及退出   處於競爭狀態的 raw 監視器的事件:等待進入,進入及退出   未處於競爭狀態的 Java 監視器的事件:等待和已完成等待   丟棄監視器  丟棄監視器   丟棄堆   丟棄對象   請求導空或復位剖析數據   JVM 初始化和關閉
 
在進行剖析時,Java 虛擬機將這些事件發送到剖析代理,接着剖析代理將期望的信息傳送
給剖析器前端,如果需要的話,剖析器前端可以是在另一臺機器上的運行進程。
 

 
最優化指南   避免爲性能而犧牲代碼的可讀性。   不能孤立地考慮性能。要權衡所需付出的努力與能夠得到的利益之間的關係。   性能是大型工程要關心的問題,但是它通常不是小型工程要考慮的問題。   使程序可以運轉應該比鑽研程序的性能有更高的優先權。一旦我們擁有了可運轉的
程序,我們就可以使用剖析器來使其更爲有效。僅當性能被確定爲是一個關鍵因素
的時候,在初始設計/開發過程期間才應該予以考慮。   不要假設瓶頸在什麼地方。而是應該運行剖析器來獲得數據。   在任何可能的情況下,儘量通過將對象設置爲 null 從而顯式地將其銷燬。有時這
可能是對垃圾回收器的一種很有幫助的提示。   程序大小的問題。僅當程序是大型的、運行時間長而且速度也是一個問題時,性能
優化才有價值。   static final 變量可以通過 Java 虛擬機進行優化以提高程序的速度。因此程
序常量也應該被聲明爲 static 和 final。
Doclets
雖然爲文檔支持開發一種工具,作爲幫助我們在程序中追蹤問題的想法有一點不可思議,但是 doclets 就具備這種令人吃驚的用處。因爲 doclet 探入了 Javadoc 解析器的內部,
它能夠得到 javadoc 解析器可以獲得的信息。有了它,我們就可以編程檢驗代碼中的類名、
域名和方法簽名,並且標記潛在的問題。
 
從 Java 源文件中產生 JDK 文檔的過程涉及到使用標準的 doclet 進行解析源文件和格式
化這個被解析文件的操作。我們可以編寫定製的 doclet 來定製我們的 javadoc 註釋的格
式。但是,doclet 允許我們做的比對註釋進行格式化要多得多,因爲 doclet 可以獲取被
解析的源文件的很多信息。
 
我們可以提取類中所有的成員信息:域、構造器、方法以及與每個成員變量相關的註釋(唉,
方法體的代碼無法獲得)。關於成員變量的細節被封裝到了特殊對象的內部,它包含關於成
員變量的屬性的信息(private、static 和 final 等)。這些信息對於探測編寫得很拙劣
的代碼會有所幫助,這些代碼包括應該是私有的但卻是公有的成員變量,沒有註釋的方法參
數以及沒有遵守命名規則的標誌符等等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章