Java程序中有邏輯錯誤,就需要使用JDB來進行調試了。調試程序在IDE中很方便了,比如這篇博客介紹了在Intellj IDEA中調試Java程序的方法。
我們課程內容推薦在Linux環境下學習,有同學問如何在命令行下調試Java程序,我們就要使用JDB了。
學習建議:Linux Bash下打開三個標簽頁
我們提倡在Linux命令行下學習Java編程。學習時在Ubuntu Bash中通過Ctrl+Shift+T
快捷鍵打開三個標簽(tab),:一個使用vim編輯代碼;一個使用javac, java(或ant, gradle...)編譯運行代碼;一個使用JDB調試代碼。
如下圖所示,這樣就不用在一個窗口中進行編輯,編譯運行和調試的切換了,能提高效率。
如上圖, 我們在Linux Bash中輸入 vim HelloJDB.java
編輯調試示例代碼:
1 public class HelloJDB {
2 public static void main(String[] args) {
3 int i = 5;
4 int j = 6;
5 int sum = add(i, j);
6 System.out.println(sum);
7
8 sum = 0;
9 for(i=0; i< 100; i++)
10 sum += i;
11
12 System.out.println(sum);
13 }
14
15 public static int add(int augend, int addend){
16 int sum = augend + addend;
17 return sum;
18 }
19}
代碼編輯完,我們按“:w”進行保存而不是“:wq”進行保存退出,這樣在編譯或調試中遇到問題就可以按Alt+1
進入第一個標簽修代碼了。
我們按Alt+2
進入第二個標簽,使用javac -g -d bin src/HelloJDB.java
對程序進行編譯。注意javac中-g參數是為了產生各種調試信息,一定要加上,否則無法調試。
我們按Alt+3
進入第三個標簽,使用jdb -classpath .:./bin HelloJDB
對程序進行調試。
調試基礎
調試程序先要學會設置斷點,這樣才能讓程序停在你感覺有問題的代碼處進行排查。學習調試我們要學會設置四種斷點:
- 方法斷點
- 行斷點
- 條件斷點
- 臨時斷點
我們在JDB中輸入help
可以查看命令列表:
上圖中的stop in 用來設置方法斷點,stop at 設置行斷點。學習過程中要經常查看幫助文檔。
上圖漢化有個錯誤,stepi
下面的下一步
應該是next
命令,這兩個都是單步執行命令,我們后面會解釋step
和next
的區別。
我們通過運行stop in HelloJDB.main
命令在main方法開始處設置斷點:
如上圖,我們輸入run
命令來運行HellJDB.class,程序會在main()的開始處停下。
此時可以用locals命令查看變量,用step命令運行下一行代碼:
看兩條locals
命令的結果,開始只有main方法的參數args,后面就有局部變量i,j的值了。
不使用locals
命令,我們可以使用print
或eval
命令來查看變量的值:
我們可以使用list
來查看運行到了源代碼的什么位置,HelloJDB.class文件和HelloJDB.java不在同一個文件夾下,我們需要使用use
或sourcepath
指出源代碼的位置,下圖中的箭頭指出代碼運行到了哪一行:
大家注意上圖是將要運行第五行,但還沒有運行。還要注意,第五行是個方法調用。我們繼續輸入step
和list
,我們發現代碼跳入16行方法體中了:
一般說來,調試時遇到方法調用,我們先看調用結果對不對,結果正確,說明方法沒有問題,就不用進入方法體了; 方法調用結果不對,我們才需要進入方法體進行調試。單步跟蹤命令next
和step
在執行一般語句時沒有區別,在執行有方法調用的語句時,next
會把方法執行完,step
會進入方法體。所以在調試時,單步執行我們要優先使用next
,這樣效率比較高。
現在已經進入方法體了,我們可以運行step up
把方法執行完,返回調用處,后面執行一般語句,你發現next
和step
沒有區別。
第九行和第十行是個循環,這兩條語句單步執行起來有點費勁。
我們可以通過stop at HelloJDB:12
在第12行設個斷點,然后運行cont
就會一下子把循環運行完並停在第十二行。cont是continue的縮寫,功能是運行到下一個斷點處停止。
我們可以用stop
或clear
命令查看設置的斷點的情況。
其實這里最好用個臨時斷點,還有,如果第9行問題出在i=80處,我們就需要條件斷點,可惜JDB不支持臨時斷點和條件斷點。
我們使用quit
或exit
可以退出JDB。
類的調試
遞歸的學習
遞歸算法是一種直接或間接地調用自身的算法。在編寫程序時,遞歸算法對解決一大類問題是十分有效的,它往往使算法的描述簡潔而且易於理解。
遞歸用於解決形式相同,規模不同的問題,能用遞歸解決的問題都可以轉化為循環。遞歸把一個大型復雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解,遞歸策略只需少量的程序就可描述出解題過程所需要的多次重復計算,大大地減少了程序的代碼量。遞歸的能力在於用有限的語句來定義對象的無限集合。用遞歸思想寫出的程序往往十分簡潔易懂。
遞歸程序有兩個要點:遞歸公式和結束條件。我們以求整數的階乘為例:
有了公式,代碼就容易寫出來了:
1 public class Factorial {
2 public static void main(String [] args) {
3 System.out.println(fact(5));
4 }
5
6 public static int fact(int n) {
7 if (n == 0)
8 return 1;
9 else
10 return n * fact(n-1);
11 }
12 }
fact(5)的遞推過程如下圖:
我們設置好斷點:
方法調用一次就會形成一個棧幀,我們在JDB中用where顯示棧幀,用up,down可以在棧幀之間跳轉。
大家用up,down 體會一下壓棧,出棧:
多線程的調試
Java API的學習
JDB 不但是個好的調試工具,也是一個好的學習工具,可以讓你了解程序的動態執行過程。
其他
JDB沒有GDB那么強大,如果想使用GDB調試Java代碼,以參考[用GDB 調試Java程序 ](http://blog.csdn.net/haoel/article/details/22893
05)。
參考資料
歡迎關注“rocedu”微信公眾號(手機上長按二維碼)
做中教,做中學,實踐中共同進步!
-
版權聲明:自由轉載-非商用-非衍生-保持署名| Creative Commons BY-NC-ND 3.0
如果你覺得本文對你有幫助,請點一下左下角的“好文要頂”和“收藏該文”