注:IDEA版本為2019.2.4
文章目錄
- 一.Debug設定及視窗介紹
-
- 1.1 Debug設定及入口
- 1.2 Debug視窗及功能簡介
- 二.Variables變量及變量視窗
-
- 2.1檢視參數值
- 2.2設定修改變量值
- 2.3檢視方法傳回值設定
- 2.4 Watches視窗參數
- 三.Evaluate Expression計算表達式
-
- 3.1計算結果
- 3.2臨時修改參數内容
- 四.Breakpoints斷點詳細設定
-
- 4.1主要參數說明
- 4.2異常捕獲及定位
- 五.斷點回退
-
- 5.1回退方式1
- 5.2回退方式2
- 六.中斷斷點
- 七.分析Java Stream操作
- 八.主動抛出異常(不修改代碼)
- 九.檢測死鎖
一.Debug設定及視窗介紹
1.1 Debug設定及入口
在設定裡勾選Show debug window on breakpoint,則請求進入到斷點後自動激活Debug視窗
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90TUkZnUyoVd5cUYwhnMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLyITN2ITNzYTMxITMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
選擇項目後,點選右邊小甲蟲圖示或者shift +F9觸發debug活動視窗
1.2 Debug視窗及功能簡介
1-斷點: 在左邊行号欄右側單擊左鍵,或者快捷鍵Ctrl+F8 打上/取消斷點。
1.1 移動斷點
要移動斷點,請将其拖動到目标行。
1.2 複制斷點
要複制斷點,請按Ctrl并将其拖動到目标行。
1.3 禁用斷點
要臨時禁用斷點而不将其從項目中删除,請按住 Alt 鍵并單擊裝訂線中的斷點圖示。
1.4 斷點分組,例如,如果需要為特定問題标記斷點,則可以将斷點分組。
在“ 斷點”對話框中(Ctrl+Shift+F8),選擇要放置在組中的斷點,然後選擇“ Move to group| <group_name> /從上下文菜單建立新的或已經存在的組名。
20-Variables: 在變量區可以檢視目前斷點之前的目前方法内的變量,詳見以下的“二.Variables變量及變量視窗”。
21-Watches: 檢視變量,可以将Variables區中的變量拖到Watches中檢視。
如果沒有顯示Variables,Watches等視窗,可以點選Debug視窗右上角按鈕選擇要顯示的視窗
22-Debug視窗欄: 如果debug視窗欄所在的底層一行工具欄不顯示,可在下圖方法中選中Tool Window Bars
23-方法調用棧: 裡顯示了該線程調試所經過的所有方法,勾選右上角的漏鬥圖示Hide Frames From Libraries按鈕,就不會顯示其它類庫的方法了,否則這裡會有一大堆的方法。
以下是核心功能介紹
2-Rerun ‘xxxx’ Ctrl+F5 : 重新運作程式,會關閉服務後重新啟動程式。
3-Update ‘XXX’ application Ctrl + F10:更新程式,一般在你的代碼有改動後可執行這個功能。而這個功能對應的操作則是在服務配置裡,如下圖,按下快捷鍵後也會彈出提示選擇操作類型。
4-Resume ProgramF9: 跳到下一個斷點,沒有的話直接運作結束。比如,你在第20行和25行有兩個斷點,目前運作至第20行,按F9,則運作到下一個斷點(即第25行),再按F9,則運作完整個流程,因為後面已經沒有斷點了。
5- Pause Program : 暫停程式。
6-Stop ‘xxx’ Ctrl + F2:停止應用,main方法中點選一下關閉,web應用連續按兩下,關閉程式。有時候你會發現關閉服務再啟動時,報端口被占用,這是因為沒完全關閉服務的原因,你就需要清除所有JVM程序了。
7-View Breakpoints Ctrl+ Shift + F8: 檢視所有斷點及斷點詳細設定,詳細說明請看 四.Breakpoints斷點詳細設定。
8-Mute Breakpoints: 啞的斷點,選擇這個後,所有斷點變為灰色,斷點失效,按F9則可以直接運作完程式。再次點選,斷點變為紅色,有效。如果隻想使某一個斷點失效,可以在斷點上右鍵取消Enabled,如圖下圖,則該行斷點失效,斷點失效後變為空心圓圈。
9-Get Thread Dump: 擷取線程的轉儲資訊,列出一些線程狀态。
10-Settings: 單擊此按鈕以打開菜單,其中包含以下選項:
Show Values Inline:開啟後可在變量旁邊檢視變量的值。
Show Method Return Values:選擇此選項可顯示最後執行的方法的傳回值。
Auto-Variables Mode:如果您希望IntelliJ IDEA調試器自動評估某些變量(斷點處的變量以及斷點前後的幾行),請選擇此選項。
Sort Values Alphabetically:選擇此選項可按字母順序對“Variables”窗格中的值進行排序 。
Unmute Breakpoints on Session Finish::選擇此選項可在調試會話完成後重新啟用所有禁用的斷點。
11-Pin Tab: 單擊此按鈕固定或取消固定目前頁籤。您可能需要固定标簽,以防止在此視窗中達到最大标簽數時自動關閉标簽。
12-Show Execution Point Alt+F10:顯示執行點,如果你的光标在其它行或其它頁面,點選這個按鈕可跳轉到目前代碼執行的行。
13- Step Over F8:步過,一行一行地往下走,如果這一行上有方法不會進入方法。
14-Step Into F7:步入,如果目前行有方法,可以進入方法内部,一般用于進入自定義方法内,不會進入官方類庫的方法。
15-Force Step IntoShift+Alt+F7:強制步入,能進入任何方法,檢視底層源碼的時候可以用這個進入官方類庫的方法。
16-Step OutShift+F8:步出,從步入的方法内退出到方法調用處,此時方法已執行完畢,隻是還沒有完成指派。
17-Drop frame:回退斷點,具體詳見 五.斷點回退 。
18-Run to CursorAlt+F9:運作到光标處,你可以将光标定位到你需要檢視的那一行,然後使用這個功能,代碼會運作至光标行,而不需要打斷點。如果光标行之前有斷點,會在此斷點上暫停。
19-Evaluate ExpressionAlt+F8:計算表達式,詳見以下 三.Evaluate Expression計算表達式。
更多調試的方法,可以在Run按鈕下檢視
二.Variables變量及變量視窗
2.1檢視參數值
- 參數所在行後面會顯示目前變量的值,在以上的Settings->Show Values Inline可以打開/關閉。
- 光标懸停到參數上,顯示目前變量資訊,點選 + 号可以檢視變量詳情。
在Variables裡檢視,這裡顯示目前方法裡的所有變量。
2.2設定修改變量值
當代碼運作到一些變量時,發現此參數有錯誤,可以右鍵選擇對應的變量,手動臨時修改此參數的值(F2),如下,
2.3檢視方法傳回值設定
設定檢視方法的傳回值如下,即可檢視調用方法的傳回值情況。
2.4 Watches視窗參數
在Watches裡,點選New Watch,輸入需要檢視的變量。或者可以從Variables裡拖到Watche裡檢視。
三.Evaluate Expression計算表達式
3.1計算結果
選中要計算的内容,在Run菜單中或者Alt+F8彈出計算表達式視窗如下。
點選Evaluate按鈕可以計算出選中内容的結果,這個表達式不僅可以是一般變量或參數,也可以是方法,調用的方法可以計算其傳回值。
3.2臨時修改參數内容
設定變量,在計算表達式的框裡,可以改變變量的值,這樣有時候就能很友善我們去調試各種值的情況。
四.Breakpoints斷點詳細設定
4.1主要參數說明
Ctrl+ Shift + F8或者點選左側工具欄圖示。
控制台輸出如下:
過濾器說明如下:
Catch class filters:捕獲類過濾器, 可以指定類名或類模式(帶*通配符的字元串)。
如果通過類名指定了過濾器,則它指向該類本身及其所有子類。通過類模式指定的過濾器指向其完全限定名稱與該模式比對的類。
句法:
使用空格分隔類名和通配符号;要排除的類,請-在類名稱前輸入 -
例如,這-java.* -sun.*意味着不得為java和sun包中捕獲的異常觸發斷點。
Instance filters: 執行個體過濾器,選擇以限制特定對象執行個體的斷點命中,文法同上。
Class filters: 類過濾器,選擇以過濾必須擊中斷點的類,文法同上。
Pass count: 用于循環中,如果斷點在循環中,可以設定該值,循環多少次後停在斷點處,之後的循環都會停在斷點處。如果同時設定了通過次數和條件,則IntelliJ IDEA首先滿足條件,然後檢查通過次數,以避免兩個設定之間發生沖突。
Caller filters: 選擇僅在從某個方法調用(或不調用)斷點時才需要在斷點處停止。
4.2異常捕獲及定位
異常斷點,通過設定異常斷點,在程式中出現需要攔截的異常時,會自動定位到異常行。
點選 + 号添加Java Exception Breakpoints,然後輸入需要斷點的異常類型,添加異常斷點,我這裡捕獲任何異常,如圖下圖。之後可以在Java Exception Breakpoints裡看到添加的異常斷點。增加過濾的類,否則捕獲的異常可能是java類包存在或者抛出的異常。
代碼中抛出空指針,出現空指針異常後,自動定位在空指針異常行。
五.斷點回退
所謂的斷點回退,其實就是回退到上一個方法調用的開始處,在IDEA裡測試無法一行一行地回退或回到到上一個斷點處,而是回到上一個方法。
5.1回退方式1
一種是Drop Frame按鈕+F9(Resume Program),回退到方法斷點處。
5.2回退方式2
第二種方式,在調用棧方法上選擇要回退的方法,右鍵選擇Drop Frame ,回退到該方法的上一個方法調用處,此時再按F9(Resume Program),可以看到程式進入到該方法的斷點處了。
但有一點需要注意,斷點回退隻能重新走一下流程,之前的某些參數/資料的狀态已經改變了的是無法回退到之前的狀态的,如對象、集合、更新了資料庫資料等等。即已經對全局狀态所做的更改将不會恢複,而隻會重置局部變量。
六.中斷斷點
有些時候,我們看到傳入的參數有誤後,不想走後面的流程了,怎麼中斷這次請求呢(後面的流程要删除資料庫資料呢…)。
可以通過Force Return,即強制傳回來避免後續的流程,如圖。也可在Run下拉菜單進入。
點選Force Return,彈出Return Value的視窗,我這個方法的傳回類型為Message,是以,我這裡直接傳回new Message()來強制傳回,進而不再進行後續的流程。或者裡面的表達式可以設定為其他null等表達式。
注:輸入表達式确定後,往往還需要按F9(Resume Program)才能完全終止請求操作。
七.分析Java Stream操作
Java 8 Streams有時可能難以閱讀和調試,因為要了解程式是如何到達特定輸出的,您可能需要插入其他斷點,并分析流中的每個轉換。
此功能僅适用于項目檔案。不能使用Java Stream Debugger調試庫或反編譯的代碼。
當調試器在Stream API調用鍊之前或之内停止時,點選跟蹤目前流鍊圖示Trace Current Stream Chain 。
在評估了目前資料流之後,您可以直覺地看到每個轉換中每個元素發生了什麼,以及它的值在經過資料流中的所有步驟時如何變化:
調試流跟蹤拆分視圖
單擊“ 平面模式”按鈕可在一個視圖中一次檢視所有操作:
調試流跟蹤平面視圖
八.主動抛出異常(不修改代碼)
IntelliJ IDEA使您可以從程式中的特定位置引發異常,而無需修改代碼。
從“ Frames”視圖中所選方法的右鍵菜單中 選擇“ 抛出異常”,然後指定表達式:
九.檢測死鎖
當兩個線程之間的沖突導緻彼此根本無法工作時,就會發生死鎖。一旦發生,可以通過檢視所有線程的 Frames來輕松發現死鎖。我們可以通過使用Thread dump來做到這一點 。如果我們知道我們正在陷入死鎖,那麼運作模式甚至比調試更可取。這是因為我們完全不會幹涉這種方式的執行,并且快照将是應用程式的Java線程轉儲的輸出。線程轉儲可以檢測死鎖并發出警告。例如,在下面的轉儲中,我們可以看到該程序在PublisherThread(卡在第44行)和SubscriberThread(在第78行)之間發現了1個死鎖。
在此示例中,我們可以看到兩個線程都被卡在等待一個鎖,這意味着另一個線程沒有釋放這些鎖。我們還可以看到兩者都在等待不同的鎖,因為同步器ID是不同的。頂部的死鎖摘要提供了更多資訊,它告訴我們什麼線程持有每個鎖。我們可以看到兩個死鎖線程持有另一個線程試圖擷取的鎖。
這應該已經為我們提供了有關死鎖如何發生的大量資訊。如果仍然不清楚我們的代碼如何達到死鎖,則可以在遇到線程轉儲提供的行之前嘗試使用斷點進行調試。當我們有什麼錯誤時,我們可以嘗試使用斷點之間的依賴關系來重制場景。
現在,我們可以 在其中一個線程上建立一個“ Suspend Thread”斷點,并使用另一個線程轉儲快照來驗證另一個線程是否達到了死鎖位置。
另一個選擇是在兩個線程上放置挂起線程斷點,并在它們之間切換。檢查的狀态Publisher,并Subscriber 在這個例子告訴我們,造成混亂的狀态。
當我們檢查鎖執行個體時,我們可以看到并發代碼實際上是正确的,但是當将它們傳遞給兩個對象時,我們混淆了讀鎖和寫鎖。檢視上圖中的鎖執行個體ID。
确實,當我們随後檢查構造(在其中注入了這些鎖)時,我們可以看到該錯誤:
ThreadGroup threadGroup = new ThreadGroup("Demo");
new Thread(threadGroup, new Subscriber(messageQueue, readLock, writeLock), "SubscriberThread").start();
//passing locks in the wrong order will cause deadlock between publisher and subscriber
new Thread(threadGroup, new Publisher(messageQueue, writeLock, readLock), "PublisherThread").start();