无题
文章目录
IDEA 调试功能说明 🛠️
Show Execution Point
Step Over
Step Into
Force Step Into
Step Out
Drop Frame
Run to Cursor
Evaluate Expression
Trace Current Stream Chain
Rerun Main
Resume Program
Stop Main
View Breakpoints 📍
Mute Breakpoints 🔇
Get Thread Dump 🧵
筛选 🗂️
调试小技巧 🔍
行断点
方法断点
更多功能点
属性断点
更多功能点
异常断点
更多功能点
临时断点
断点条件 📌
模拟异常 🚨
更优雅的模拟异常方式
多线程调试 🧵
示例代码
调试演示
改进方法
修改变量 🔧
断点执行代码/方法/表达式 🔄
远程调试 🌐
设置步骤
进行调试
远程调试配置参数解释
重要参数
启动项目
IDEA远程调试配置
测试过程
更多功能 🚀
总结 🌟
在探索 IDEA 的强大功能之前,我们先来简单了解一下它的界面布局。IDEA 的 Debug 控制台位于整个界面的左下方,这个控制台是所有调试操作的中心。通过这个控制台,你可以查看程序运行时的变量,控制执行流程,甚至动态修改代码!
IDEA 调试功能说明 🛠️
Show Execution Point
快捷键: Alt + F10
功能描述: 回到当前激活的断点处。如果你在调试过程中失去了当前断点的位置,只需一键点击,IDEA将立即把视图带回至断点所在行,确保你能迅速回到问题的核心位置。
这种方式不仅保留了原文的技术性描述,而且通过添加动作的直接效果(“立即把视图带回”),使得说明更加生动和易于理解。此外,使用emoji也帮助在视觉上突出这一部分,增加文章的友好感和易读性。
Step Over
快捷键: F8
功能描述: 单步调试,逐行向下执行。当执行的代码行调用其他方法时,此功能将不会跳入那些方法内部,而是直接跳过。这是日常 Debug 中使用频率最高的功能之一,允许开发者在不深入每个方法的情况下,快速过滤代码执行流程。
Step Into
快捷键: F7
功能描述: 深入探索。此功能允许你进入当前执行点所调用的方法体内部,无论是你自己定义的方法还是第三方库的方法。特别注意,它不会进入JDK的核心方法中,使你能专注于应用级别的代码调试。
Force Step Into
快捷键: Alt + Shift + F7
功能描述: 强制深入。此功能扩展了 Step Into 的能力,允许你强制进入任何方法体内部,包括JDK的核心方法。当你需要详细了解底层实现或第三方库与JDK的交互时,这将是一个非常有用的工具。
Step Out
快捷键: Shift + F8
功能描述: 快速返回。当你已深入到一个方法体内部并需要返回到上一级代码执行点时,使用此功能。它是 Step Into 或 Force Step Into 的完美配合工具,允许你在完成方法内部的调试后迅速跳出,继续其他部分的调试工作。
Drop Frame
功能描述: 回溯重置。这个功能允许你将执行回溯到当前方法的调用处,并将所有相关变量的值重置到那一时刻。这是在深入调试时的一个重要工具,尤其当你需要重新评估方法执行的影响时非常有用。
使用条件: 该功能只在当前方法有上级方法时可用。例如,如果你处于 main 方法中,该按钮将显示为灰色,无法使用。
Run to Cursor
快捷键: Alt + F9
功能描述: 精准执行。此功能允许你直接运行代码至光标所在位置,无需设置额外的断点。这是进行快速测试或当你想专注于特定代码段时的理想选择,使调试过程更加高效和直观。
Evaluate Expression
快捷键: Alt + F8
功能描述: 动态计算。这个工具允许你在调试时期执行任何合法的表达式,非常适合测试假设、验证数据或临时修改变量值。它提供了一种灵活的方式来探索和理解正在运行的代码的行为。
Trace Current Stream Chain
功能描述: 流追踪优化。这个功能专为Java Stream操作设计,它允许你追踪并可视化当前Stream流的处理链。只有当你的光标位于Stream操作的代码上时,此按钮才会激活,提供直观的方式来理解和调试复杂的Stream操作。
Rerun Main
快捷键: Ctrl + F5
功能描述: 重新执行。此功能允许你快速重新启动主程序的调试会话,无需手动停止并重启,极大提高调试效率。这是在进行长期或复杂的调试任务时尤其有用的功能,允许开发者持续追踪代码改动的影响。
Resume Program
快捷键: F9
功能描述: 继续执行。使用此功能可以从当前断点恢复程序的运行,直到遇到下一个断点或程序执行完毕。这是调试过程中用于控制程序流的核心功能,允许开发者在需要时暂停查看程序状态,随后继续执行以观察程序行为的变化。
Stop Main
快捷键: Ctrl + F12
功能描述: 立即停止。此快捷键让你能够随时中断当前运行的程序。它是在测试或调试时快速结束程序执行的有效方式,特别是当遇到无法预期的行为或需要终止长时间运行的操作时。
View Breakpoints 📍
快捷键: Ctrl + Shift + F8
功能描述: 管理断点。此快捷键打开一个专门的断点管理窗口,允许你查看、编辑、启用或禁用所有设置的断点。这是优化调试流程的关键工具,使你能够精确控制程序在何处暂停执行,以便更详细地检查和修改代码行为。
Mute Breakpoints 🔇
功能描述: 暂停所有断点。此功能允许你一键停用所有活跃的断点,使程序能够不受干扰地继续运行至结束或至下次手动暂停。这是在需要快速验证程序整体行为或进行性能测试时非常有用的工具,避免了频繁的中断带来的不便。
Get Thread Dump 🧵
功能描述: 获取当前线程Dump。此功能允许你捕获并查看当前所有线程的状态信息,非常适合用于分析程序的并发行为和诊断死锁或其他线程相关问题。通过详细的线程Dump,开发者可以深入了解每个线程的执行路径及其互动,从而优化程序性能和稳定性。
筛选 🗂️
功能描述: 进一步细化信息展示。在处理复杂的线程Dump或大量数据时,筛选功能可以帮助你快速定位关键信息,简化调试过程,确保可以集中注意力解决当前最紧迫的问题。
调试小技巧 🔍
行断点
行断点的图标是一个圆形的红点,在需要断点的代码行头点击,即可添加断点。这是最基本也是最频繁使用的断点类型,允许你在代码执行到特定位置时暂停,非常适合逐步跟踪和问题定位。
方法断点
方法断点允许你在特定方法的入口处设置断点。当该方法被调用时,无论从哪里调用,执行都会在这里暂停。这对于调试使用了策略、模板方法等设计模式的应用非常有帮助。
常见使用场景:
当阅读源码或编写业务需求时,我们经常会使用设计模式如策略或模板方法。调试这些模式时,通常需要确认哪个具体实现被执行。通过在接口或抽象方法上设置方法断点,可以轻松跟踪到具体的实现。
如下图所示,接口 Service 有两个具体的实现:ServiceA 和 ServiceB,分别实现了接口的 method 方法。在Main方法中实例化 ServiceB 并调用时,通过方法断点可以直接进入 ServiceB 的 method() 方法的执行。
接口Service有两个具体的实现:ServiceA和ServiceB,分别实现了接口的method方法,调试的过程中就可以将断点打在接口的method方法上;当我们在Main方法中实例化了ServiceB,断点就自动进入到ServiceB的method()方法了;
接口Service
public interface Service {
void method();
}
1
2
3
ServiceA
public class ServiceA implements Service{
@Override
public void method() {
System.out.println(“Service A”);
}
}
1
2
3
4
5
6
ServiceB
public class ServiceB implements Service{
@Override
public void method() {
System.out.println(“Service B”);
}
}
1
2
3
4
5
6
Main
public class Main {
public static void main(String[] args) {
Service serviceB = new ServiceB();
serviceB.method();
}
}
1
2
3
4
5
6
更多功能点
Condition
用于输入特定的表达式进行过滤,可以设置条件,仅当条件满足时,断点才会触发。这使得调试更加灵活和针对性。
Watch
你可以选择在方法入口 (Method entry) 或方法退出 (Method exit) 时激活断点。至少选择一个,可以更精确地控制断点的触发时机。
Emulated
此选项用于模拟断点,提高调试过程中的性能,尤其在处理复杂或资源密集的应用时非常有用。
Method entry
设置此断点在方法开始执行时激活,允许你观察到方法被调用的瞬间及其传入参数。
Method exit
设置此断点在方法完成执行并即将返回时激活,有助于检查方法的输出和执行后的状态。
属性断点
在属性行的左侧点击即可添加一个小眼睛图标的属性断点,它用于监听某个属性的读写变化。当该属性被访问或修改时,程序将在这些点暂停,让你可以检查属性值的变化及其影响,这对于追踪状态错误或理解复杂逻辑非常有价值。
更多功能点
Condition
此功能允许输入表达式进行过滤,只有当表达式的条件满足时,断点才会被触发。这是控制断点激活的精确方式,特别有用于复杂的调试场景。
Watch
这里的设置允许你精细地控制对特定属性的监控,可以独立选择对字段访问或修改的监控:
Field Access
当选中此项时,每当属性被读取时,断点将触发(不关注写入操作)。
Field Modification
当选中此项时,每当属性被修改时,断点将触发(不关注读取操作)。
异常断点
异常断点是一种强大的调试工具,允许你在指定异常发生时自动暂停执行,这对于快速定位和解析程序中出现的错误至关重要。
设置方式:
第一步,使用快捷键 Ctrl + Shift + F8 打开断点配置窗口;
第二步,点击窗口左上角的 + 号;
第三步,选择 Java Exception Breakpoints;
第四步,在列表中添加你需要监控的异常类型,例如:ArithmeticException;
第五步,开始Debug运行。当程序抛出指定的异常时,执行会自动暂停,允许你直接查看和处理引发异常的代码行。
这些功能的组合不仅提高了调试效率,还极大地简化了异常管理和错误跟踪的过程,使得开发者可以更专注于代码的改进和优化。
更多功能点
Condition
使用此功能可以输入表达式进行过滤,确保断点只在特定条件满足时触发。这提供了更细粒度的控制,允许开发者聚焦于特定的问题或情况。
Watch
这部分的设置允许开发者根据异常的捕获状态选择性地激活断点:
Caught Exception
此设置使断点只在异常被明确捕获(try-catch块内)时触发。
Uncaught Exception
此设置适用于异常未被捕获的情况,即异常逃逸出最近的try-catch块时。
临时断点
临时断点是一次性的断点,设计用来在触发一次后自动取消。它特别适用于那些只需要临时检查或验证特定行为或值的场景。
设置方式:
第一步,在代码中设置普通断点。
第二步,使用快捷键 Ctrl + Shift + F8 打开断点配置窗口。
第三步,在断点列表中找到对应的断点。
第四步,勾选 Remove once hit 选项。
第五步,开始Debug运行。当断点被触发一次后,它会自动被取消,从而避免在同一位置多次中断执行。
这些高级功能增强了IDE的灵活性,使开发者可以根据具体需求调整断点行为,提高调试效率。
断点条件 📌
设置断点的触发条件是阅读源码或修复Bug时经常使用的功能。例如,在研究Spring源码和探索Bean生命周期时,你可以根据Bean的name设置断点条件,确保只在操作指定对象时才触发断点。
示例应用:
在一个for循环中,你可能只想在i是2的倍数时进入断点。在Condition中填入表达式 i % 2 == 0 来设置这一条件。
在一个0-10000的循环中,如果你希望仅在i等于5000时触发断点,可以在Condition中设置 i == 5000,忽略其他情况。
设置过程:
第一步,在代码中设定一个普通断点。
第二步,右键点击断点标记,打开操作界面。
第三步,在表达式输入框中填入需要的条件,例如在循环时只有偶数才断点,可以输入 i % 2 == 0。
通过这种方式,断点条件的设置不仅提升了调试的效率,还帮助开发者聚焦于特定的问题点或关键行为,从而更精确地控制程序的执行流程。
模拟异常 🚨
在开发过程中,特别是在处理事务操作时(如使用@Transactional注解),经常需要验证异常处理逻辑,以确保如预期般能够触发回滚。虽然在代码中手动抛出异常是一种常见的测试方法,但这种做法可能不够优雅且存在风险,如误将测试异常代码提交到生产环境,可能导致严重后果。
更优雅的模拟异常方式
幸运的是,IDEA提供了一种更安全、更优雅的模拟异常的方法,允许开发者在不修改代码的情况下,通过调试工具直接抛出异常。下面是操作步骤:
操作步骤:
第一步,在需要模拟异常的方法中设置一个断点。
第二步,以Debug模式运行代码,让执行暂停在设置的断点处。
第三步,在Debug窗口的Frames面板中找到对应的断点。
第四步,右键点击,选择Throw Exception选项。
第五步,在弹出的对话框中输入你希望抛出的异常类型,例如RuntimeException,并填写异常消息,比如"异常了"。
第六步,点击ok,IDEA将在当前执行点抛出指定的异常。
这种方法的优势在于它可以精确控制异常的抛出时机和类型,无需更改任何代码,同时在测试完成后也无需进行代码清理,极大地降低了因遗留测试代码导致的风险。
多线程调试 🧵
多线程开发常见的挑战之一是无法预测线程间的执行顺序。由于线程调度由操作系统控制,不受程序直接管理,这可能导致调试过程中线程执行的顺序和预期不一致,尤其在逻辑复杂的情况下,这种不确定性会增加调试的复杂度。
示例代码
public class Main {
public static void main(String[] args) {
System.out.println(“0 main start”);
new Thread(() -> {
System.out.println(“1 hello”);
}, “thread1”).start();
new Thread(() -> {
System.out.println("2 world");
}, "thread2").start();
System.out.println("3 main end");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
在这个示例中,虽然System.out.println(“0 main start”)可以保证作为第一个输出,但其他打印语句(1、2、3)的输出顺序由于线程调度的不确定性而无法预测。
调试演示
默认情况下,IDE的断点suspend设置为All,这意味着当任一线程触发断点时,所有线程都会暂停。这种设置虽然有助于全面检查程序状态,但可能导致对线程执行顺序的混淆。
改进方法
为了更好地控制线程调试的流程,可以将断点的suspend选项设置为Thread。这样,只有触发断点的那个线程会暂停,其他线程将继续执行,从而允许开发者专注于单个线程的状态和行为,按线程顺序逐个调试。
设置过程:
在断点上右键点击,打开断点设置。
修改suspend选项从All变更为Thread。
这样设置后,每个线程将独立暂停和继续,使得调试更为清晰,尤其是在涉及多线程交互的复杂场景中。
通过这种方法,开发者可以更有效地追踪和理解各个线程的执行细节,提高多线程应用的调试效率。
修改变量 🔧
在调试过程中,有时会遇到变量值因逻辑错误而与预期不符的情况。在这种情况下,重新启动整个调试会话既耗时又低效。IDEA允许开发者直接在断点处修改变量的值,然后继续执行后续步骤。这一功能极大地提升了调试的灵活性和效率,尤其是在需要快速测试不同变量值影响的场景中。
断点执行代码/方法/表达式 🔄
在断点处,IDEA不仅允许查看变量值,还可以执行代码、方法或表达式。这使得开发者能够动态地测试和修改程序行为,而无需修改源代码并重新编译。
代码执行
可以在断点处执行任何代码片段,比如修改变量、调用方法或者执行复杂的运算。这是检验代码修改效果或实现快速修正的有效方式。
方法执行
直接在断点处调用任何可用的方法,并观察其输出。这对于验证方法的正确性及其对程序状态的影响尤其有用。
表达式评估
这允许在断点处计算任何有效的表达式,从而实时查看其结果。评估表达式是理解当前程序状态和预测程序行为的关键工具。
这些高级调试功能为开发者提供了极大的便利,使他们可以在保持程序运行的同时,对代码进行即时检查和修改,从而有效地节约时间并提高调试效率。
远程调试 🌐
远程调试是一种强大的技术,允许开发者在本地环境中调试运行在远程服务器上的应用程序。这对于处理线上环境中出现的问题特别有用,因为它允许开发者快速定位并修复Bug,而不必直接在生产环境中进行操作。
注意事项: 进行远程调试时,非常重要的一点是必须确保本地代码和线上代码的版本完全一致。如果版本不一致,断点可能无法正确触发,从而导致调试失败。
设置步骤
添加一个用于远程调试的接口
在你的应用中添加一个简单的REST控制器,用于触发调试点。例如:
@RestController
public class RemoteDebugController {
@GetMapping(“/debug”)
public Integer debug(Integer p) {
System.out.println§;
return p;
}
}
1
2
3
4
5
6
7
8
这个接口提供了一个简单的方法来触发调试,并检查传递的参数。
将代码打成jar包
使用Maven或类似工具将应用打包,确保所有依赖都正确包含。例如:
mvn clean package -Dmaven.test.skip=true
1
这个命令会生成一个jar包,排除了测试代码,准备用于部署。
IDEA设置远程调试启动项
在IntelliJ IDEA中设置远程调试配置:
打开 Run -> Edit Configurations…
点击左上角的 + 添加一个新的配置,选择 Remote
配置名称和远程连接设置(端口、主机等)
这些设置将为你的IDE与远程服务器之间的调试会话建立连接桥梁。
进行调试
部署好远程应用并设置完IDEA后,你就可以启动远程调试会话。只要远程应用在运行,且调试端口被正确映射和开放,就可以在本地IDE中像处理本地应用一样调试远程应用。这包括设置断点、查看变量、逐步执行代码等。
远程调试是解决生产环境问题的强大工具,但应谨慎使用,确保不对生产环境造成不必要的影响。同时,确保调试通道的安全,避免潜在的安全风险。
远程调试配置参数解释
远程调试是一个高级功能,它允许开发者在本地环境中调试运行在远程服务器上的应用。以下是设置远程调试时需要配置的几个关键参数的详细说明:
重要参数
Name
此参数为配置的名称,主要用于标识不同的远程调试配置,内容可以随意填写。
Host
指定远端服务所处的机器IP地址。在本地测试时,可以填写127.0.0.1。在实际应用中,应填写远端服务所处的真实IP地址。
Port
指定远端调试的端口,该端口将用于远程调试会话的连接。
远端服务运行时的JVM参数
这些参数由IDEA工具提供,需要在远程应用启动时加入到JVM启动参数中,以便开启远程调试功能。
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5555
1
这个配置示例中,transport=dt_socket表示使用socket通信,server=y表示作为服务器监听,suspend=n表示启动时不暂停,address=5555指定监听端口。
启动项目
为了演示,以下是在CMD窗口下启动测试项目的命令,确保使用了上述生成的JVM参数:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5555 -jar spring-boot-001-hello-world-0.0.1-SNAPSHOT.jar
1
启动日志中出现Listening for transport dt_socket at address: 5555表明远程调试配置正确且已经启动监听。
IDEA远程调试配置
下图展示了在IDEA中如何配置远程调试:
测试过程
左侧为jar包运行的控制台;
右上方为IDEA的调试界面;
右下方为浏览器,用于模拟客户端请求。
当客户端发起请求时,IDEA将自动进入断点。执行通过后,控制台将打印出相应的日志。
注意: 在线上环境中进行调试时,务必给断点设置条件,例如只有特定测试账号才触发断点,以避免影响真实用户的请求和体验。
通过以上设置和操作,如果远程代码存在bug,开发者可以直接在本地IDEA中进行调试,这大大简化了问题的定位和修复过程。
更多功能 🚀
上面列举了绝大部分常用的Debug功能,但这仅仅是冰山一角。IDEA还提供了许多高级功能,可能不是日常必用,但在特定情况下极为有用。探索并熟悉这些工具,可以让你的调试工作更加高效和精确。
总结,工欲善其事,必先利其器。熟练掌握这些调试工具,可以让你的编程工作事半功倍,更快地解决问题,并有更多时间专注于创新和优化代码。🛠️🎯🔧