这是非常紧张的一周。承载该课程的新YouTube 频道的订阅量呈爆炸式增长;它刚刚进入第三周......
课程网站现已上线;你可以在那里看到整个课程,尽管我一直在添加视频并且做了大约 1/3 的工作。
现在,它有 3 小时 17 分钟的内容。我还有一个小时的内容准备添加,并且我正在处理更多内容。我很确定课程完成后将超过 6 小时。
我还在制作其他一些有趣的视频,例如关于保护自己免受序列化攻击的视频。我将在接下来的几周内写一篇完整的博客文章来介绍它。
如果您有任何问题、想法或想法,我很乐意听取您的意见。以下是本周的视频和文字记录。
欢迎回到 Scale 调试的第三部分,我们将学习像专业人士一样寻找错误!
在本节中,我们将讨论作为调试基石的监视表达式。这非常重要,我稍后会再次讨论这个主题。
手表区域是屏幕底部的区域
在 IntelliJ 中,我们还可以在代码旁边嵌入监视表达式。监视是调试器最重要的功能之一。这就是我们如何查看调试器中正在发生的事情。
但我会比这更深入。特别是对于对象标记,这是有史以来最酷的调试器功能之一。
你是否曾经从一个方法返回时只是想,“那个方法返回了什么?”
这很常见,尤其是当返回值未存储在变量中时。幸运的是,IDE 可以选择为我们保存该值,以便我们可以立即检查它!
通过启用此选项,我们可以看到所有未来方法的返回值。如果我们进入isPrime
方法然后退出,您将能够在此处底部看到该方法的返回值。
计算表达式是我们使用得不够多的调试器的一项很酷的功能。
我们可以从右键单击菜单启动评估表达式对话框,然后键入任何有效的 Java 表达式。这是一个强大的工具,可以调用任何方法、进行算术运算,甚至可以更改变量的值。
如果您需要模拟一些在当前代码中难以测试的东西,那么您可以在这里玩转平台并测试“狂野的理论”。
这与我们在较新版本的 Java 中拥有的 REPL 非常相似,但它在很多方面都更好,因为我们可以在应用程序的上下文中执行代码。
如果我有一个返回错误值的方法,我通常会将调用复制到评估对话框中并尝试调用的各种组合以查看“什么有效”。
只需尝试所有选项而不重新启动可以为我们节省很多时间!
您可以使用Alt-F8
组合键启动此对话框。
IntelliJ 中的监视能力绝对是惊人的。
IntelliJ 让我们通过从上下文菜单中选择“Add Inline Watch”将手表直接嵌入到 IDE 编辑器中。这是一个惊人的功能,据我所知,这是 JetBrains 独有的。
选择后,手表会出现在我们添加内联手表的行的右侧,这使得使用代码进行评估变得容易。这在反复返回同一条线路时非常方便。
我们还可以使用标准 watch,它将添加带有其他变量的元素。这对于我们想要跟踪大面积代码的对象很有用。在我们前进的过程中,关于手表区域我有很多话要说,但现在,让我们暂时搁置。
设置值是我在调试时经常忘记使用的功能。
太可惜了,因为它太强大了。我们可以通过右键单击它并选择设置值来设置任何字段的值。
我们也可以使用F2
来加速
我可以将值更改为任意值。这也适用于我可以分配现有值或调用创建方法、新语句或我想要的任何表达式的对象。
这是一个非常强大的功能,我们可以动态地改变对象以重现我们想要测试的状态。
我们可以将此功能与我们之前讨论的跳转到行结合起来,并通过许多不同的排列来测试方法。即使是那些通常无法重现的。一个很好的例子是我拥有的只能在 Windows 上运行的代码。但我有一台 Mac。
我只是更改指示当前操作系统的静态变量的值并测试该代码。
对象标记是我们将在本课程中讨论的最酷的功能之一,它几乎不为人知。
这有点微妙;首先,我们将为Thread.currentThread()
添加一个 watch,它返回表示当前线程的对象实例。
如您所见,我可以在手表中看到当前线程。
现在,我可以一次又一次地运行这个方法并查看当前线程;该方法是否始终从同一个线程执行?
好吧,我可以查看线程 ID,是的。一样的。所以,它可能是线程安全的。但是我该如何验证呢?
我通常在一张纸上写下对象 ID 或变量的指针,然后检查它们是否是相同的值。这很痛苦,而且无法扩展。我多久可以一次又一次地按继续?
在右键单击菜单中,我选择“标记对象”并输入任意名称。 MyThread
在这种情况下,一旦我这样做了,我就可以按 OK
这将立即用新标签替换当前线程的值。因此,我们可能会错误地认为这只是一个监视表达式的名称。它不是。我们声明了一个新变量并将其命名为MyThread
。
我们将 watch 表达式的当前值复制到该变量中。我们现在可以像对待 IDE 中的大多数变量一样对待该变量。
我们可以在这里评估价值,得到我们想要的一切。请注意 IntelliJ 添加的_DebugLabel
后缀以避免命名冲突,但除此之外,我们可以对该对象调用任何操作,例如获取名称甚至访问私有字段名称。
但这变得更好了......
让我们为这个方法添加一个断点,一个完全标准的断点,就像我们之前所做的那样。
这将是一个标准的条件断点;我们很快就会深入讨论这些,但是现在,您只需要知道我可以定义一个条件来确定断点是否会停止。
让我们放大。
让我们输入条件;我可以将MyThread
与线程的当前值进行比较。请注意,由于MyThread
的值独立于Thread.currentThread()
的原始 watch 语句,因此此条件将相应地运行。
因此,如果当前线程确实不同,断点将在此时停止。
这在处理许多对象时非常有用。在这种情况下,我可以从字面上检查该方法是否会被同一个线程命中。我可以用它来比较任何对象,而不是将它们的指针写在一张纸上!
是的。我真的会拿着一张纸坐下来复制指针地址,以确保如果我再次看到它,我就做对了。这在很多方面都更好!
我经常将其与 JPA 等 API 一起使用,有时我们可能会有两个具有相同标识的对象实例。这真的很难检测。只需标记一个对象,然后您就可以立即看到它是一个不同的实例。
由于这种情况显然是单线程的,断点将永远不会再次命中。但这对于非常复杂的案例非常有效,并且是一个非常有用的工具!
接下来,我们将深入探讨断点和它们可以做的令人惊奇的事情。这是一个你不想错过的深入视频。
如果您有任何疑问,请使用评论部分。谢谢!