改变程序的执行流程
最后修改时间:2023 年 9 月 7 日调试应用程序时,您通常遵循程序的正常流程。但是,在某些情况下您需要偏离它。为了重现某些条件或测试程序如何处理问题(例如,处理值null
或处理异常),可能需要这样做。
此外,当您需要跳过程序中与当前正在检查的问题无关的特定部分时,这也很方便。
返回上一个堆栈帧
IntelliJ IDEA 允许您回退到程序执行流中的上一个堆栈帧。例如,如果您错误地走得太远,或者想要重新输入错过关键点的方法,这可能很有用。
将鼠标悬停在要重置的框架上,然后单击出现的“重置框架”按钮。
笔记
请注意,已经对全局状态所做的更改不会恢复,并且仅重置局部变量。
使用断点表达式
为了改变程序的流程,您可以使用非挂起断点,在命中时计算表达式。例如,当您想要在调试期间自动修改变量时,这很有用。
public class AlteringFlow {
private static boolean readyToExit = false;
private void printHello() {
System.out.println("Hello");
//more code goes here
readyToExit = true;
}
public static void main(String[] args) {
AlteringFlow af = new AlteringFlow();
af.printHello();
if (!readyToExit) main(null); // line n1
}
}
在示例中,重置readyToExit
为false
将使该printHello
方法一遍又一遍地执行,直到我们禁用重置它的断点。
此外,还可以利用断点表达式来添加一些您只想在调试期间使用的逻辑。
public class AlteringFlow {
private static boolean addDebugLogic;
public static void main(String[] args) {
System.out.println("Hello");
if (addDebugLogic) new Debug().doSomething();
}
}
class Debug {
void doSomething() {
// code goes here
}
}
强制从当前方法返回
您可以在方法到达return
语句之前退出该方法并使其返回任意值。当问题与方法的返回值有关而不是与它的生成方式有关时,这很有用。强制返回可帮助您测试程序如何处理返回值,而无需重现导致这些值的条件。
当您使用Force return时,当前执行点之后的指令将被忽略。
确保在“框架”选项卡上选择当前方法,然后右键单击选项卡中的任意位置并选择“强制返回”。
如果该方法返回一个值(其返回类型不是
void
),请指定该值或将计算该值的表达式。表达式在局部上下文中求值,并且可以使用任何已声明的局部变量。返回值必须符合方法的返回类型。
如果执行点当前位于
try
、catch
、 或finally
块中,并且其中有代码行finally
尚未执行,请选择是否要跳过它们。
抛出异常
IntelliJ IDEA 允许您从当前执行的方法中抛出异常或错误。当您想要测试程序中如何处理特定类型的异常而无需重现原因或修改代码时,这非常有用。
确保在“框架”选项卡上选择当前方法,然后右键单击选项卡中的任意位置并选择“抛出异常”。
创建异常(这可以是该方法未处理的任何
Throwable
包含和检查的异常)。Error
不要使用throw
关键字。
重新加载修改后的类
有时,当您对代码进行更改时,您希望立即查看它们在工作应用程序中的行为方式,而无需关闭进程。HotSwap机制允许您重新加载在调试会话期间更改的类,而无需重新启动整个应用程序。
重新加载单个文件
右键单击已修改文件的编辑器选项卡,然后选择“编译并重新加载文件”。
您还可以使用“设置”| “编译后重新加载类”选项配置重新编译类后自动重新加载类。构建、执行、部署 | 调试器| 热插拔。可以启用/禁用自动重新加载,或者您可以对其进行配置,以便调试器询问您是否在每种特定情况下重新加载文件。
重新加载所有文件
转到“运行”| 调试操作| 重新加载更改的类。
如果在“设置”| “重新加载类之前构建项目”选项已启用,则会自动进行重新编译。构建、执行、部署 | 调试器| 热插拔。如果禁用此选项,则需要在重新加载之前重新编译文件(Build | Recompile )。CtrlShiftF9
热插拔限制
由于VM设计的原因,HotSwap有以下限制:
仅当修改方法体时它才可用。不支持更改签名。
不支持添加和删除类成员
如果修改的方法已经在调用堆栈中,则只有在程序退出修改的方法后,更改才会生效。在那一刻之前,方法体保持不变,并且框架被标记为已过时。
如果您想消除标准 VM 施加的限制,可以使用动态代码演进 VM,它无限支持在运行时重新加载类。
感谢您的反馈意见!