优化的'printf'调试

阅读其他语言: English Español 한국어 Português

‘printf’调试,作为最常见的调试技术之一,尤其受欢迎,因为它几乎是在人们编写第一个程序时就会直观学会的。

‘printf’调试非常易于使用,因为你不需要任何特殊工具。当你遇到最初的错误,甚至还不知道什么是调试器时,自然而然会想到让程序一步步打印变量,在控制台中跟踪执行流程。

尽管这是一种最基本调试技术,但即使是经验丰富的开发者也频繁使用它。它可以帮助你调查各种问题,如不理想的程序段、不一致的状态、多线程问题等。

如我前面所提,这种技术并不需要使用特定的工具,如IDE。然而,如果你正在使用一个IDE,它可以让你在记录程序状态时更加高效。

Info icon

本文展示的是IntelliJ IDEA的功能。 其他IDE可能有或没有类似功能。 如果你使用的是其他工具,请考虑查阅其文档, 查看这些功能是否同样可用。

实时模板

IntelliJ IDEA提供了实时模板,用于最常见的调试日志模式。要使用调试日志的实时模板,输入相应的缩写并按Tab键,IntelliJ IDEA将生成打印语句并插入到光标位置。

让我们来看几个例子。

记录方法参数


public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

        // 在这里输入 'soutp',然后按Tab

    return null;
}
public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

    System.out.println("in = " + in + ", mask = " + mask + ", newColor = " + newColor);

    return null;
}

记录值


public static double coolMethod(double parameter) {
    double a = Math.random();
    double b = Math.random();

    // 在这里输入 'soutv',按Tab,然后选择值

    return a * b * parameter;
}
public static double coolMethod(double parameter) {
    double a = Math.random();
    double b = Math.random();

    System.out.println("b = " + b);

    return a * b * parameter;
}

记录方法入口


public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

    // 在这里输入 'soutm'

    return null;
}
public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

    System.out.println("ImageUtils.recolor");

    return null;
}

日志断点

使用打印语句进行调试的一个缺点是它们引入了手动管理的开销。你不能快速地开启和关闭它们,并且绝对不想意外地提交并在生产环境中运行它们。

因此,如果需要为调试目的记录某些内容,建议使用日志断点,因为它们更易于管理。

编辑器边距中显示为黄色圆圈的日志断点 编辑器边距中显示为黄色圆圈的日志断点

要设置日志断点,按住Shift键,然后点击边距。与常规断点不同,它不会暂停程序的执行,而是输出到控制台。

默认情况下,它是表明程序到达这一行的消息。如果你更愿意记录当前堆栈跟踪或自定义表达式的结果,也可以在断点设置中的求值并记录 (Evaluate and log)复选框旁的选项中使用。

带有自定义表达式在'求值并记录'字段中,以及清除的'挂起'复选框的断点设置对话框 带有自定义表达式在'求值并记录'字段中,以及清除的'挂起'复选框的断点设置对话框
Info icon

注意日志表达式的使用。评估那些引起副作用的表达式可能是新bug或意外行为的源头。此外,当在热点代码中使用时, 它们可能会显著减慢你的程序。

当日志断点变得很多时,可以在断点 (Breakpoints)对话框(运行 | 查看断点Run | View Breakpoints)中跟踪和管理它们:

显示项目中所有断点,按类型分组的'断点'对话框 显示项目中所有断点,按类型分组的'断点'对话框

你甚至可以为它们创建自定义组:

右击'断点'对话框中的断点显示包含'移至组'选项的上下文菜单 右击'断点'对话框中的断点显示包含'移至组'选项的上下文菜单

这有助于集中管理断点。例如,你可以创建一个与特定错误相关的组并保存以备后用。当问题解决时,只需将其关闭。这样,如果问题再次出现,你不必从头开始重新创建一切。只需再次打开该组即可。

频繁事件的日志记录

对于程序执行过程中经常发生的事件,记录每一次事件可能是多余的。这不仅会用消息淹没控制台, 而且大量的I/O交互可能会显著降低调试会话的速度

包含大量相似消息的控制台,如'Mouse moved to 380, 183' 包含大量相似消息的控制台,如'Mouse moved to 380, 183'

对于这类事件,使用合格次数 (Pass count) 功能可能很有帮助。你可以在断点 (Breakpoints)对话框中访问它。

断点设置对话框,其中'合格次数'字段设置为100 断点设置对话框,其中'合格次数'字段设置为100

设置合格次数 (Pass count)到特定值后,相应的断点将仅在每n次命中时触发,确保日志记录不会成为麻烦。

总结

无论你是插入打印语句还是设置日志断点进行调试,现代工具都具有改善调试体验的特性。通过这篇文章,我希望确保你了解这些使整个过程更加愉快的小技巧。

祝调试愉快!

all posts ->