最好的IDEA debug長文?看完我佛了

YourBatman發表於2021-02-07

前言

你好,我是A哥(YourBatman)。

最近寫了幾篇IntelliJ IDEA系列的文章,反響蠻好。我想了下,因為並非是分享什麼破解方法、推薦外掛、主題這種蛋炒飯式譁眾取寵的文章,而是真實對工作有幫助,對提高工作效率很有用的內容。同學們對使用IDEA還是有不少痛點,或者姿勢不夠正確優雅,一直以來A哥堅持寫些不隨波逐流、有一定深度專欄文章,哪怕只是個工具IDEA而已。

上篇文章 文末做了說明,本計劃IDEA系列告一段落,但有收到幾條上百字的留言和私信,覺得有些讀者確實很用心在看,所以決定寵粉再幹幾篇。對於IDEA系列,工具嘛,研究原理沒有意義,而是站在使用者的角度,介紹正確姿勢和最佳實踐,用工具提效是唯一目的。

當然,也有私信問我我的主題咋設定的挺好看?用了哪些好用的外掛?自定義的外掛如何開發?之類的,我認為這種確實沒必要單獨分享嘍,因為用谷歌百度一下就可以找到一推拉,各行大佬寫的文章多了去了

本篇介紹IDEA除錯debug,因為它確實很重要。會不會debug,有沒有debug的意識,懂不懂 debug 的技巧,是有沒有入門程式設計的重要標誌。 關於IDEA debug除錯的文章我在CSDN裡早已發表過,反響還不錯(看來有痛點的人不少呀):

今天我就把它“搬過來”,並做“增強”改動分享出來,希望你喜歡。

本文提綱

版本約定

  • IntelliJ IDEA:2020.3.2

小插曲:IDEA剛釋出了其2020.3.2這個小版本,啟動圖換成了20週年圖,IntelliJ IDEA 20週歲啦,為期2天的週年慶活動對開發者免費開放,感受一下:

正文

Debug除錯對IT從業者不是個陌生概念,工作中經常會用到它,這無關乎於初級、中級、高階程式設計師。除錯程式的方式有多種,如:輸出日誌、增加輔助變數、拆分函式體、斷點除錯等等,本文將介紹的是斷點除錯 -- 一種最行之有效的除錯方法。準確的講,本文講述是使用IntelliJ IDEA斷點除錯。

Debug用來追蹤程式碼的執行流程,通常在程式執行過程中出現異常時,啟用Debug模式可以分析定位異常發生的位置,以及在執行過程中引數的變化。除此之外,我們也可以使用Debug模式來跟蹤程式碼的執行流程來學習優秀的開源框架。

斷點除錯有多重要?

俗話說編碼5分鐘,debug2小時,從這句話就能體現出除錯的重要性,畢竟它佔據你“大部分”的時間。

為了真實的體現出它的重要性,我“引經據典”,找來了幾個資深行業經驗的大佬用引用他們的話來表述:

  1. 除錯技巧比編碼技巧更為重要,因為花費在除錯上的時間往往比編碼還多,學到的東西比編碼中學到的更豐富
  2. 除錯技能重要性甚⾄超過學習⼀門語⾔
  3. 不會除錯的程式設計師,肯定編制不出任何好的軟體

我把關鍵詞都加粗劃重點了,其重要性可見一斑。大佬尚且這麼認為,何況是我等?所以,本文好好閱讀O(∩_∩)O哈哈~

什麼是斷點?

突然被這麼一問,是不是腦袋懵懵的?

一個天天都在用的“東西”,若是真要你對它下個定義說給別人聽,估計一時半會還解釋不清。當然嘍,大道至簡,領會其要義能熟練使用才是硬道理。本文作為一篇“嚴肅”的技術文章,自然需要先把斷點這個概念用文字描述出來。

斷點:為了除錯而故意讓程式暫停的地方。它是一種附加在原始碼上面的特殊標記,在debug模式下可以觸發特定動作,如暫停執行、列印執行緒堆疊、計算表示式的值、變數跟蹤等等。斷點的設定和取消全人為手動管理,若不手動處理(刪除)將會和專案一直存在。

如果你看過前兩篇文章,一定能解釋為何它會一直存在專案裡。建議你前往參閱,電梯直達

可見,斷點的核心要義是暫停程式,從而在暫停那時刻就可以看到上線文的變數情況、IO情況、執行緒情況等資訊,進而更深入的瞭解程式,及時發現問題和追蹤到錯誤的根源。

斷點引數

斷點並不是孤立存在的,它也可以有引數,從而定製出不同的斷點行為,讓其能在不同條件下生效,這個引數就叫斷點引數

我們平時用得比較多的條件斷點,它就是斷點引數的最典型應用。當然除了條件斷點,其它的斷點型別也是可以定製化引數的。那到底有哪些斷點型別可以使用和定製呢?那麼接下來就步入到本文主體內容,開始進入更有意思的部分啦。

斷點的基本使用

應該沒人不會打斷點吧,即使你是產品經理(產品經理莫名躺槍,手動狗頭~)。

打斷點最簡單最直接的方式就是在你想設定斷點的哪一行程式碼的最左邊窗欄滑鼠左鍵單擊一下,完成後能看到一個小紅點,就表示斷點設定成功啦,再點選一下就取消。形如這樣:

因為我的IDEA介面簡潔,儘可能的去掉了“按鈕”,所以平時我自己是使用到大量的快捷鍵來操作IDEA,打斷點也是如此經常用快捷鍵去完成。當然嘍,很多時候也用滑鼠的啦,畢竟滑鼠處理還是有其很大優勢的。

說明:我的快捷鍵是Ctrl + Shift + B,僅供給你參考

管理斷點

管理斷點包括新增、刪除斷點。

對於少量斷點來講,滑鼠一個個的點選給它刪除掉是可以的。但若打了“大量”的斷點在程式碼裡(比如看xxx原始碼的時候),這時讓去一個個找來刪除是不太現實的,畢竟你可能自己都忘了哪兒有斷點。這個時候一個管理頁面/視窗就顯得格外的重要了,在IDEA中提供了這樣的視窗,你有多種方式開啟它:

  1. 選單欄方式:Run -> view breakpoints,缺點是路徑太長太麻煩
  2. Actions方式:雙擊shift調出Actions視窗,輸入view breakpoints即可開啟
  3. 任意斷點處滑鼠右鍵:選擇more即可開啟管理視窗。缺點是:你至少得找到一個斷點作為抓手(當然嘍你可以任意處隨意打一個點進去也成)
  4. 除錯視窗:該開啟方式下面會提到
  5. 快捷鍵方式:毫無疑問,這是我最為推薦的方式嘍

在這個管理頁面,你可以對斷點進行增刪改

說明:我的快捷鍵是Ctrl + Shift + F8,僅供給你參考

如何debug模式執行?

額,這講得是不是有點過於簡單了點。

啟動Debug模式執行的方式有多種,比如工具欄的蟲子小圖示按鈕、程式方法入口左鍵點選、選單欄、右鍵選單欄等等,下面簡單演示下:

據我瞭解,很多同學最常用的方式是點選上方工具欄右上角的蟲子圖示,因為我“沒有”這個圖示,所以“教程”中就不演示了。A哥平時99%情況下都是使用快捷鍵方式啟動程式,因為我認為那是最迅速和便捷的(當然不一定適合你)。

此功能我的快捷鍵分為兩大類

  1. 執行右上角當前選中的入口類。它有一組快捷鍵
  2. Ctrl + Shift + Alt + enter:Run執行
  3. Ctrl + Shift + Alt + \:Debug執行
  4. 因為很多時候需要從新的入口啟動程式,做Spring Boot工程開發可能體會不到(入口只有一個),但在做教程、Demo的時候程式入口是經常變化的,所以不可能每次都還人肉去改啟動類,效率太低。為此我就新設定了這組快捷鍵
  5. Ctrl + Shift + Alt + [:Run執行,滑鼠焦點所在作為入口
  6. Ctrl + Shift + Alt + ]:Debug執行,滑鼠焦點所在入口

另外,若要區分本次是Run執行還是Debug執行,除了看右上角小蟲子圖示外,更好的方式看底部控制檯視窗啟用的是哪個。這樣看的優點是:即使同一份應用啟動多次,也能快速看出來哪些debug哪些run。
Run模式執行

Debug模式執行

值得一提的是:debug模式執行,若沒有任何斷點被啟用(比如你壓根就沒打斷點),效果和run模式啟動是一樣(但控制檯視窗不一樣,因此日誌輸出的位置也就不一樣)。

除錯視窗詳解

除錯視窗是我們斷點除錯的操作皮膚,熟練的使用此皮膚推提高效率和掌握更多技巧非常重要。先來認識下它:

此操作皮膚上按鈕不少,對Debug除錯有多熟練很大程度上是由操作此皮膚的熟練度決定的。

除錯按鈕

最常用的一排按鈕,入門必備。

一共9個按鈕,從左往右依次解釋下:
1.
Show Execution Point:回到當前啟用的斷點處。效果:若你滑鼠現在在別的頁面/別的類上面,點選它快速“歸位”
2.
Step Over步過:也叫單步除錯,一行一行往下走,若這一行是方法也不會進入裡面去。這個應該是平時使用得最多的按鈕了,沒有之一。所以,建議記住你的快捷鍵來提高效率哈
3.
Step Into步入:進入方法體內部。這裡的方法指的你自定義的方法or三方庫的方法,不會進入到JDK官方的方法裡(如上面的System.out.println()這種它是不會進去的)
4.
Force Step Into強制步入:能進入任何方法,包括JDK的。一般檢視底層原始碼才會用到它
5.
Step Out步出:它是搭配(Force) Step Into一起使用的,當通過step into進入到方法體內部想出來時,一般有兩種方案:單步除錯慢慢出來,另一個就是step out(推薦)
6.
Drop frame:回到當前方法的呼叫處,同時上下文內所有的變數的值也回到那個時候。該按鈕能夠點選的前提條件是:當前所處的方法有上級方法,如果你是main方法裡,那麼按鈕就是灰色嘍
7.
Run to Cursor執行到游標處:你想要程式碼在哪裡停一下,就把游標放在哪就成。這個功能實在太好用了,大大緩解了密密麻麻的斷點,強烈推薦
8.
Evaluate Expression表示式計算器:看圖示就是個計算器嘛,所以你可以在這裡執行任何合法的表示式

Trace Current Stream Chain跟蹤當前Stream流:只有程式碼停在Stream流語句上,此圖示才點亮可以被點選。這是IDEA提供的由於除錯Stream流的殺手鐗級別的功能,放在文下詳細解釋

這一排按鈕非常重要,甚至是最重要,一定要熟練掌握,可以大大提高除錯程式碼的效率,親測有效。

服務按鈕

把最左邊一豎排定義為服務按鈕,為除錯過程提供服務。

一共10個,但都比較簡單和好理解。同樣的從上到下過一遍:

  1. Rerun xxx:關閉當前程式,重新執行
  2. Modify Run Configuration:顧名思義,修改執行的配置。點選此按鈕的效果同點選右上角的框框:

點選會彈出這個配置視窗:

每份執行期配置都是具名且唯一的,互相隔離。執行配置可修改的項非常多,大概如下:

說明:我截圖的頁面可能和你不一樣,因為我用的是最新版的IDEA,此頁面在2020.3版本做了改版

  1. Resume Program:恢復程式。當斷點啟用時程式“停止”了,點選這個按鈕就是恢復的意思。它給到的效果是:跳到下一個斷點(用這句話解釋貌似更容易理解些),若後面沒有斷點就直接執行結束了。這個按鈕非常常用
  2. Pause Program:暫停程式。嗯,只要你現在“卡”在斷點處,那麼狀態就是Pause的狀態。這時候就有疑問了,難道這個按鈕一直是灰色不可點狀態?有啥用呢?我網路上看了看,幾乎沒人能夠解釋它的作用,這裡A哥嘗試給你解釋下,用張圖給你整得明明白白,服服帖帖:

  1. Stop xxx:不解釋

  2. View Breakpoints:開啟斷點管理視窗。文上已詳細解釋了此視窗的用法

  3. Mute Breakpoints:這個按鈕挺有意思的,作用是讓所有斷點變為灰色,也就是說讓它們失效。它是一個批量操作,操作物件是所有斷點,而不可針對於某一個。若你現在不想把所有斷點刪除,但又不想它們阻攔你,那麼可用這個按鈕實現

  4. Get Thread Dump:拿到當前執行緒的dump,可以檢視到當前執行緒的狀態。如下圖:
    main執行緒sleep了一把

    子執行緒當前狀態為Runnable

  5. Settings:開啟設定選單。屬於高階使用,每一項開啟後有什麼效果,放在文下解釋

  1. Pin tab:如果你這會除錯xxx這個程式很頻繁,那麼把它“釘”上會更有助於效率提升

方法呼叫棧

顯示當前方法(位於棧頂)所經過的所有方法。

說明:點選右上角的小漏斗圖示可以不顯示類庫的方法,只顯示你自己寫的方法,方便除錯

變數區Variables

在此區域可以檢視當前斷點上下文範圍內的所有變數值(即使不在本類內也可以點過去檢視哦),包括static靜態的。

值得注意:此區域裡的變數IDEA會自動呼叫其toString()方法,因此若你遇到正常執行只輸出一句日誌,debug輸出多句這種case很可能就是這個情況哦。

Watches變數跟蹤

有的時候變數很多,而只需要重點關注某幾個變數,就可以使用Watches。

除了以上這些,還有什麼動態改變變數值set Value,跳轉到原始碼處jump to source等都是非常實用的功能,這就留你自己開發和實驗哈。

為何除錯視窗沒自動開啟?

有同學遇到過這個情況:明明斷點啟用了(程式暫停了),但是那個“操作皮膚”並沒有出來,怎麼破?

話不多說,檢查你的這個配置項是勾選狀態即可。這個狀態IDEA預設是勾選上的,一般不用操心。

斷點除錯的奇淫巧技

最後,站在使用層面,介紹些非常實用的“奇淫巧技”給你,這些小技巧可拿來就用。

強制返回(中斷debug)

場景描述:除錯時,當我走到第三步就發現了問題,這個時候並不希望走完後續流程(比如因為前面有bug後續流程會有刪除資料操作等等),這個時候怎麼處理?

咔嚓,Stop程式。是的,很長一段時間裡我也是這麼幹的,確實能達到目的。直到我發現了一個更優雅的方法:Force Return,效果為:強制返回方法返回值(自己給個值)來避免後續的流程。

條件斷點

指定斷點的啟用條件,都能稱作條件斷點。一般情況下,在行斷點下給定一個計算表示式,結果為true就啟用斷點這是最常用的方式。因為上面已有案例,這裡省略

多執行緒除錯

多執行緒程式的好處固然不用多說,但總所周知它除錯起來是比較困難的,比如這段:

public static void main(String[] args) {
    // 共放3個"令牌"
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

    // 模擬多個執行緒去搶
    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            try {
                String name = Thread.currentThread().getName();

                System.out.println(name + ",準備搶令牌");
                cyclicBarrier.await();
                System.out.println(name + ",已搶到");
            } catch (Exception e) {
            }
        }, "執行緒" + i).start();

    }

}

這個時候如果你想研究await()方法的實現,需要具備的前提條件是多個執行緒進入,因此需要hold住多個執行緒。若只是在await()這一行打個普通的行斷點,那結果是這樣子的:

所有執行緒都是Running狀態,顯示這是不可能的,因為總共只有3個另外,拿完了其它的都得等待才對,所以這個根本就不是真實的執行場景,也就不可能跟蹤到await()方法裡面去探究其實現。

為了模擬出這種場景進行除錯,就對斷點阻塞條件設定為這樣:

再次執行程式,執行緒情況如下:

快速計算表示式

都知道除錯皮膚裡的Evaluate Expression可以計算表示式/變數的值,但那畢竟還得彈個窗稍顯麻煩,其實還有更為方便的方式:

用滑鼠操作,效率指數級提升。這個操作方式是:滑鼠指標選中表示式(IDEA智慧自動選中) + 滑鼠左鍵單擊。當然嘍,如果你想執行自定義的不存在於程式碼中的表示式,那必須調起視窗來操作。

Stream流除錯

Java 8的流行,徹底讓流式程式設計走進我們的視野。使用Stream程式設計的好處眾多,但一直被大家詬病的是難以閱讀和難以除錯,特別是後者。

為了除錯它,我們經常需要插入其它斷點,並分析流中的每個轉換,不可為不麻煩。還好IDEA提供了處理該痛點的“能力”:當偵錯程式在Stream API呼叫鏈之前或之內停止時,點選Trace Current Stream Chain這個圖示即可以“非常好看”的圖形化方式展示出來,一目瞭然:

主動丟擲異常

需求場景:你寫了一個全域性異常元件,現在想測試它生效情況如何,那麼時候你就需要主動丟擲這種異常,一般的做法是形如這樣:

// 自己在程式內主動throw一個
throw new NullPointerException();

// 或者構建個表示式
int i = 1/0;

這種做法均有一定的程式碼侵入性,用後還得刪除。其實IDEA還提供了一種更為優雅的解決方案:


掌握了IDEA斷點除錯的基本技能,下面進入到本文深水區:斷點型別。難度不高,依舊是使用層面的事,但由於很多同學並不知道,因此是你用於超車的好材料。

四大斷點型別

對於打斷點,估計大部分同學都只會左邊滑鼠單擊這種最基礎的方式。所以,看到這個小標題估計你得再懵一次吧。what?斷點還有種類?

若你也是隻在程式碼左邊滑鼠單擊打上“小紅點”,然後嘎嘎就是幹,空中轉體720度向後翻騰三週半......一把唆的選手,那麼接下來就坐穩嘍,準備發車。

這麼個姿勢也許能幫你定位50%以上的問題,但還有另外一半的case呢?如for迴圈除錯,Stream流除錯,lambda除錯、異常除錯等這些場景,用那“一把唆”的方式就很難搞定甚至說搞不定了。斷點是幫我們快速定位問題的,不同的場景打上合適的斷點將能事半功倍。

殊不知,IDEA給我們開發者提供了非常的斷點型別,以應對不同場景下的除錯。在對應的場景下使用合適正確的斷點型別,能夠大大提高除錯的效率,從而別人加班你下班,效率就是時間,而時間就是生命。

如圖,IDEA把斷點分為四大型別(截圖中只有三類):

  1. Line breakpoint(行斷點):圖中紅色小圓圈。顧名思義,在指定程式碼行設定斷點
  2. Field watchpoint(屬性斷點):圖中紅色小眼睛。打在類的屬性(static or 非static)上的斷點,作用是在該屬性讀取和寫入時啟用
  3. Method breakpoint(方法斷點):圖中紅色小菱形。標記在方法簽名的那一行,在該方法執行的入口/出口處被啟用
  4. Exception breakpoint(異常斷點):紅色小閃電。這是一個特殊但很好用的斷點,當程式丟擲指定異常時會啟用異常斷點。和其它斷點不同,異常斷點是專案全域性的,它不需要打在具體某一行上

下面就到了“啃硬骨”的時候了,來吧。

行斷點Line breakpoint

使用得最最最廣泛的斷點型別,平時大部分情況下都使用此種斷點。

從“教程”中可以看到該斷點有很多的設定項,也就是有很多的斷點引數可以配置,來了解下。

斷點引數

因為這是第一個介紹斷點引數的型別,因此會說得詳細些,這樣子後面相同功能的引數就不用再贅述了。對照這個截圖頁:

  • Enabled:不解釋。但需注意:若此項不勾選上,小紅點並不會消失,而是由實心的變為空心的,當然嘍,一般情況下並不會動此項
  • Suspend:眾所周知,斷點啟用時會阻塞程式的繼續執行,從而阻塞當前執行緒。但是當你發現它是個核取方塊的時候,有沒有被詫異到?並且,並且,並且你還可以根本就不勾選它,有何區別:
    • 若不勾選選中:此斷點相關活動(如打日誌等)依舊正常進行,只是不阻塞程式
    • 若勾選中:
      • All(預設):阻塞該程式內所有執行緒

      • Thread:只阻塞當前斷點所線上程
        不勾選Suspend

        如上圖,不勾選Suspend:執行緒14和執行緒15正常執行,“暢通無阻”
        勾選Suspend-All

        如上圖,勾選Suspend-All:在斷點處,所有執行緒都被阻塞了,統一給我等待。

  如上圖,勾選Suspend-Thread:method1的執行緒被阻塞,但是並不影響另外一個執行緒呼叫method2。

試想一下,既然“勾選Suspend-Thread”影響更小,那為何IDEA預設幫你選擇All而不是Thread呢?原因是這樣子的:除錯的目的就是讓程式“慢下來”,最好是靜止下來方便分析問題。否則,其它執行緒如果仍舊繼續保持執行的話,可能一會這個請求改掉這個資料一會改掉那個資料,增加了不可控性。不確定的增加從而大大增加除錯難度和定位問題的難度,所以索性上個“同步鎖”來得省心,因此預設選中Suspend-All是合理為之。

說明:很多時候我們需要用本機連線測試環境打斷點進行遠端除錯,若在這個case下強烈建議你使用Thread模式,否則你懂的

  • Condition: 斷點被啟用的條件。你可以在此處書寫表示式,只有表示式返回true時此斷點才會被啟用
    • 條件斷點嚴格來講不屬於一種斷點型別,屬於斷點引數決定的,很多型別的斷點都可加條件

  • Log:它有三個選項,是checkbox哦。也就是說可都選,也可都不選,預設一個都不選
    • Breakpoint hit message:斷點啟用時輸出提示日誌
    • Stack trace:斷點啟用時輸出程式呼叫棧資訊
    • Evaluate and log:選擇需要輸出計算表示式的值。你可選擇當前可達的變數,如本例的main函式入參args等
  • remove once hit:斷點啟用一次後就立馬給移除嘍,也就是所謂的臨時行斷點,下面來介紹下它

還有視窗裡最右邊的這塊條件:

見名之意,一系列過濾器:過濾例項、過濾類、過濾呼叫者等等,一般這些們幾乎不會使用(至少我目前是還沒用過的),所以就一筆帶過。

使用場景

行斷點一般配合單步除錯一起使用,在看框架原始碼、定位基礎問題等使用得特別多,是最需要掌握的一種斷點型別,沒得商量。

臨時行斷點Temporary line breakpoint

它也屬於行斷點的一種,只是引數不一樣而已。由於它比較特殊,所以單摘出來說道說道。建立普通行斷點,然後把Remove once hit核取方塊勾選上即是一個臨時行斷點,效果如下:

這種斷點型別,實際使用場景其實很少。

屬性斷點Field watchpoint

此類斷點是打在屬性上的,成員屬性和靜態屬性均可。它不是小紅點,而是個紅色“小眼睛”。

斷點引數

如圖,此種斷點型別特有個watch引數,兩個可選值的含義為:

  • Filed Access:讀取此屬性時(寫入時不管)
  • Filed madification:寫入此屬性時(讀取時不管)

使用場景

當想知道xxx屬性的賦值是誰時,由於程式太龐雜沒法知道斷點打哪兒從哪開始跟蹤,這個時候使用屬性型別的斷點一下子就搞定了,非常的方便。

方法斷點Method breakpoint

斷點必須打在方法簽名的那一行,顏色形狀是個紅色的小菱形。

斷點引數

Watch有三個可選值:

  • Emulated:模擬。作用:提高除錯效能,因此預設情況下使用。官方建議:僅在除錯遠端程式碼或在沒有行號資訊的native方法或類中設定斷點時,才建議禁用此選項
  • Method entry:進入方法時啟用斷點
  • Method exit:出去方法時啟用斷點

若entry和exit都勾選,那在進入之後和出去之前都會啟用斷點

使用場景

對於此種斷點型別,可能你會說沒啥卵用。畢竟自己在方法頭尾打個行斷點就能達到同樣效果,沒必要單獨搞個型別嘛。

其實,它的殺手鐗級使用場景是把此種型別斷點打在介面方法上,這樣子不管哪個實現類方法被呼叫,都會啟用斷點,是不是特別給力。

異常斷點Exception breakpoint

比較小眾,但並不代表不重要。在我理解它比較小眾,可能大多數同學不知道如何打一個異常斷點,因為它不是滑鼠單擊就能輕鬆搞定。

上面介紹了異常斷點它是一種全域性斷點型別,因此並不能在程式碼處直接單擊,而是隻能在管理視窗裡統一新增:

和其它斷點型別相比,至少有如下不一樣:

  1. 建立斷點只能通過斷點管理視窗建立,而不能通過滑鼠點選方式
  2. 建立完成後,程式碼欄處不會有任何顯示(沒有紅色小圖示),直到它被啟用時才會出現紅色小閃電
  3. 異常斷點作用於全域性:本例中任何地方丟擲了NullPointException都會啟用此斷點

斷點引數

Notification有兩個可選值:

  • Catch excetion:只有當你自己try-catch了這個異常才會啟用斷點
  • Uncatch excetion:只有當你自己不try-catch時才會啟用斷點

預設情況下這兩個都會被勾選上,也就是說任何情況下發生此異常,都會啟用斷點。

使用場景

知曉了異常斷點的作用和觸發條件,使用場景就有啦。比如當你的程式丟擲了一個異常,但是一時半會你並不知道是哪行程式碼引起的,這個時候通過增加異常斷點的方式可以實現迅速的問題定位。

4種斷點圖示對比

每種斷點型別都有自己對應的圖示,且有不同的狀態。我從官網趴了一張對比圖,總結得特別好,在這裡一併分享給你:

遠端除錯(遠端Debug)

現在大都是微服務架構方式,每個微服務一般會有N多個上/下游依賴,如此以至於給除錯帶來了很大困難,畢竟你幾乎不可能在本地同時把依賴都啟起來用IDEA做除錯。所以,遠端除錯來了,它是除錯分散式系統的一個利器。

遠端除錯:顧名思義,使用本地IDEA除錯遠端程式碼(一般為QA環境,線上環境不可能開啟除錯埠的)。那麼如何開啟遠端除錯呢?

開啟步驟

開啟遠端除錯只需要兩步即可:

第一步:讓遠端部署的那個應用支援遠端除錯,也就是暴露遠端除錯埠。方式方法為在應用啟動時加上對應的JVM引數即可,JDK版本不同引數也不一樣

  • JDK 9+:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*?{debug_port}
  • JDK 5-8:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${debug_port}
  • JDK 4:-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=${debug_port}
  • JDK 3-:-Xnoagent -Djava.compiler=NONE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=${debug_port}

第二步:用IDEA建立一個remote執行配置,填上遠端主機的ip + 暴露的除錯埠即可。操作路徑為:Edit Configurations -> Add New Configuration ->

萬事俱備,點選debug執行,控制檯裡能看到如下字樣就證明你連結成功了:

值得注意的是:遠端除錯時請確保你原生程式碼和遠端程式碼一模一樣,以達到最佳效果。

傳統Tomcat如何開啟遠端除錯?

若你是個Spring Boot應用,那麼在jar -jar時加上JVM引數即可,那麼如果是要使用傳統的tomcat方式部署呢?這個時候找到傳統tomcat的啟動指令碼startup.sh

#!/bin/sh
os400=false

...

PRGDIR=`dirname "$PRG"`
EXECUTABLE=catalina.sh

...

exec "$PRGDIR"/"$EXECUTABLE" start "$@"

為了加上我們們的JVM引數,只需要在exec xxx之前新增一個變數值即可(以JDK8為例):

JPDA_OPTS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=具體的埠號’

注意:這個key名稱必須是JPDA_OPTS。

有好奇心的你可能不禁就要問了:為何加個JPDA_OPTS引數就行了呢?也沒見exec xxx使用它呀,其實不然,下面簡單解釋下,不展開。

exec執行時引用了變數 $EXECUTABLE,它代表的是就是catalina.sh這個檔案,該檔案裡面有大量變數判斷指令碼,當然包括負責對JPDA_OPTS解釋:

#!/bin/sh

cygwin=false
darwin=false
...
if [ "$1" = "jpda" ] ; then
  if [ -z "$JPDA_TRANSPORT" ]; then
    JPDA_TRANSPORT="dt_socket"
  fi
  if [ -z "$JPDA_ADDRESS" ]; then
    JPDA_ADDRESS="localhost:8000"
  fi
  if [ -z "$JPDA_SUSPEND" ]; then
    JPDA_SUSPEND="n"
  fi
  if [ -z "$JPDA_OPTS" ]; then
    JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND"
  fi
  CATALINA_OPTS="$JPDA_OPTS $CATALINA_OPTS"
  shift
fi
...

關於JVM除錯平臺JPDA更多知識點,可自行用谷歌百度一下學習學習

嵌入式Tomcat如何開啟遠端除錯?

這不就是Spring Boot應用形式麼?所以,如何開啟,不用再廢話了吧~

總結

人和動物的最大區別之一是人會使用工具,且善於使用工具。工具被創造出來,使命就是提效的,畢竟我們不可能用記事本去寫Java程式吧。

IntelliJ IDEA作為最為流行的JVM平臺IDE,我們應該儘可能的去挖掘出它的效用,既然作為整合開發環境,其實很多功能都可以一站式搞定,在一個平臺裡做很多資料都能打通。比如IDEA的rest介面除錯、資料庫對映、Shell終端等等,應付平時的開發一般搓搓有餘,推薦使用,畢竟軟體啟得越多電腦越卡不是。

用IDEA和會用IDEA是兩個層次,除了程式碼本身,最常用的開發工具也是值得花番心思的。大道至簡,知易行難,知行合一,得到功成!

本文思考題

本文所屬專欄:IDEA,後臺回覆專欄名即可獲取全部內容,已被https://www.yourbatman.cn收錄。

看完了不一定懂,看懂了不一定會。來,文末3個思考題幫你覆盤:

  1. 斷點能打在類上嗎?
  2. IDEA能設定哪幾種型別的斷點呢?各有什麼場景?
  3. 如何用IDEA debug除錯測試環境的應用?

推薦閱讀

System.out.println("點個贊吧!");
print_r('關注【BAT的烏托邦】!');
var_dump('私聊A哥:fsx1056342982');
console.log("點個贊吧!");
NSLog(@"關注【BAT的烏托邦】!");
print("私聊A哥:fsx1056342982");
echo("點個贊吧!");
cout << "關注【BAT的烏托邦】!" << endl;
printf("私聊A哥:fsx1056342982");
Console.WriteLine("點個贊吧!");
fmt.Println("關注【BAT的烏托邦】!");
Response.Write("私聊A哥:fsx1056342982");
alert("點個贊吧!");

A哥(YourBatman):Spring Framework開源貢獻者,Java架構師,領域專家。文章不標題黨,不譁眾取寵,每篇文章都成系列去系統的攻破一個知識點,每個系列可能是全網最佳/唯一。注重基本功修養,底層基礎決定上層建築。現有IDEA系列、Spring N多系列、Bean Validation系列、日期時間系列......關注免費獲取

相關文章