4.4 调试Java程序
Eclipse平台内置了一个Java调试器。该调试器不仅提供诸如单步执行、设置断点、检查变量,以及暂时挂起和恢复线程等标准调试功能,而且提供了代码片段编辑测试窗口页面和远程调试两个特殊的功能。
4.4.1 调试视图
JDT调试器是Eclipse二进制文件中包含的一个标准插件。它有一个特殊的调试视图,开发人员可以在该视图中管理工作台中程序的调试和运行。
知识:
Eclipse平台虽然主要是一个Java开发环境,但其体系结构也支持其他编程语言,例如,调试视图同样也适用于C/C++语言。
在调试视图中可以通过设置断点、挂起线程、单步执行和检查变量来控制程序的运行。从调试视图的界面中,可以看到调试视图主要显示以下信息:
(1)正在运行的程序的进程。
(2)被挂起的正在进行调试的线程的堆栈帧信息。
(3)程序中每个线程都作为一个节点显示。
知识:
堆栈帧的意思就是在程序运行时调用的方法以及它内部的变量等信息。
调试视图包括进程视图和控制台视图。进程视图显示正在运行以及最近被终止的进程。控制台视图允许开发者通过标准输入和输出流与正在运行的进程进行交互操作。
在对Java程序进行调试时,可以先对程序进行运行环境设置,如果对运行环境没有特殊的要求,省去不管它,在工具快捷栏中单击调试按钮 旁边的倒三角形,在弹出的下拉菜单中选择【调试方式→Java应用程序】命令,如图4-28所示。
图4-28 启动调试
注意
打开调试的方法和打开运行的方法类似,读者可以参照4.2.2小节打开运行的方式。
如果要设置程序调试的参数,可以选择【运行→调试…】,将弹出如图4-29所示的窗口,可以对其进行参数设置。该窗口和设置运行的窗口(如图4-21所示)一样。
图4-29 调试配置
参数设置好后,单击【调试】按钮,将会在工作台中显示调试视图,如图4-30所示。
图4-30 调试视图
4.4.2 调试方法
1.本地调试
本地调试是最简单且最常用的一种调试方法。代码编写和编译完成之后,就可以通过工作台的菜单栏上的【运行→调试…】命令来启动程序。以此方法启动程序,就可以在客户机调试器和Java程序之间建立连接,以便使用断点、单步控制或表达式求值等方式来调试程序。
注意
为了便于设置行断点或单步执行,在编写程序时应该尽可能不要将多个语句放在同一行上,这是因为这些调试器功能部件是以行为基础来运行的。
(1)暂挂线程和继续线程
调试开始后,用户可以将正在执行的线程挂起,以便查看该线程堆栈帧的信息。要暂挂,首先得在调试视图中选择线程,然后单击调试视图工具栏中的【暂挂】按钮,线程将被挂起。调试视图显示该线程当前的调用堆栈,并且调试视图中的编辑器中也会突出显示该堆栈帧对应的代码,这行代码就是线程被挂起那一刻程序运行到的地方。如图4-31所示。
图4-31 调用堆栈
线程暂挂时会自动选择线程顶部的堆栈帧(即最近被调用的地方),“变量”视图会显示堆栈帧中的变量以及它的值,复杂的变量可以被展开以便查看其成员的值。
线程既可以被挂起,也可以恢复执行。
要继续执行暂挂的线程,在调试视图的工具栏中单击【继续】按钮(或者按F8键),线程将继续执行,但是将不再对该线程显示堆栈帧,同时也清除了“变量”视图中的变量和值。如图4-32所示。
图4-32 继续线程
(2)单步遍历控制程序
线程被挂起后,可以使用单步控制逐行执行程序。如果在这个过程中遇到断点,那么将在断点处挂起并且终止单步执行。
在调试视图中,系统提供了几种单步执行程序的操作,如下所示:
· 单步跳过。不用进入调用的方法内部,而是在该方法结束后下一个方法执行前挂起。在调试视图中的工具栏中单击【单步跳过】按钮(或按F6键)即可完成该操作。
· 单步跳入。进入调用方法的内部,和单步跳过刚好相反。在调试视图中的工具栏中单击【单步跳入】按钮(或按F5键)实现该功能。
· 单步返回。顾名思义,就是如果进入了方法调用,并且看到了期望的结果,但是希望尽快从该方法返回,此时将用到“单步返回”功能。在调试视图中的工具栏中单击【单步返回】按钮(或按F7键)实现该功能。
· 使用单步执行过滤器/单步调试。为了避免在调试过程中出现中断的情况,可以使用该功能。中断是由于在没有源代码的情况下使用单步执行进入调用方法而导致的。中断发生时,会弹出一个窗口,要求输入源代码的位置。在使用只包含类文件的代码库时会发生这种情况。在过滤器中设置的各种包和类在单步进入只有二进制文件的类库时,调试器都不会弹出要求输入源代码位置的窗口。调试器也不会单步进入过滤器里的包和类。
Eclipse平台还提供了对单步执行过滤器设置的功能。在工作台的菜单栏中选择【窗口→首选项…】命令,将会弹出首选项窗口,在该窗口的左边目录树中选择【Java→调试→单步执行过滤】选项,如图4-33所示。对应地在右边窗口中将会出现“单步执行过滤”的设置界面。
图4-33 单步执行过滤
在该窗口中,用户可以添加类、包和过滤器,还可以启动或禁用过滤器。
注意
在调试视图中,也可以右击,在弹出的菜单里选择关闭或打开过滤器。
(3)查看和修改变量的值
有几种方法可以用来检查程序中的变量。对于简单的变量,只需要在Java编辑器中将鼠标移到变量名上即可,这样会自动打开一个文本框并显示该变量的信息,包括该变量当前的值。例如,将鼠标停放在StringsDemo类中变量“len”的上面(不需要单击),就会出现如图4-34所示的界面。
图4-34 查看简单变量的信息
这种方法对于一些简单的变量是很方便的,但是对于一些复杂的变量,这种方法只会显示对象的ID和它的类型,虽然这些信息也很重要,但是它没有提供变量的值。还有与该类型相关的任何信息(如Javadoc注释)也会显示出来,如图4-35所示。
图4-35 Javadoc注释
对于一些复杂变量的值,可以使用变量视图来查看。变量视图显示当前范围内(也就是堆栈帧的上下文)的所有变量,并给出了它们的值。默认情况下,变量视图位于调试视图的右边,和断点视图、表达式视图并列,如图4-36所示。
图4-36 变量视图
使用变量视图还可以修改变量的值。在变量视图中,选中某个变量右击,在弹出的菜单中选择【更改值…】命令,如图4-37所示。然后在弹出的对话框中输入值,单击【确定】按钮就可以修改变量的值。
图4-37 修改变量的值
注意
对于复杂的变量,可以选择变量的一个特定成员进行修改。
2.断点
断点是调试程序的重要手段,断点可导致程序线程的执行暂挂。用户可以通过断点视图中的上下文菜单来启动和禁用断点。断点可以显示在编辑器的垂直标尺上。
当程序运行到一个可用的断点时,它就会被挂起。可用的断点用一个蓝色的圆圈表示。一旦在虚拟机上载入了类并且安装了断点,可用的断点就会用蓝色的圆圈加上一个钩表示,如图4-38所示。
图4-38 断点显示
不可用的断点不会导致线程挂起,它用一个白色的圆圈表示。
添加断点非常简单,在想要添加断点的代码左方的垂直标尺上双击,即可添加断点,如果出现蓝色圆圈表示成功添加断点。或者在垂直标尺上右击,在弹出的菜单栏中选择【切换断点】命令,如图4-39所示,也可添加断点。
图4-39 添加断点
当调试到有断点的地方时,线程就会被挂起,调试器会自动选择被挂起的线程,并且将线程堆栈里的信息在调试视图里显示出来。而在调试视图的编辑器中,设置断点的那一行代码也会被突出显示。
当不需要断点时,可以方便地将其删除。只要在编辑器中的垂直标尺上双击那个蓝色圆圈(断点),就会删除该断点。或者选择【切换断点】命令也可以删除断点。
如果要频繁地在一处添加和删除断点,可以使用启用或禁用断点。启用一个断点后,程序线程会在这个断点挂起;禁用该断点后(图标变成白色圆圈),线程就不会在该处挂起。
(1)方法断点
方法断点只适用于二进制文件。在Java程序里,它们适用于类文件(如.class文件)。添加方法断点的步骤如下:
1在“大纲”视图中打开一个类,选择一个想要加入方法断点的方法。
2右击该方法,在弹出的菜单中选择【切换方法断点】命令,如图4-40所示。
图4-40 选择【切换方法断点】
3断点添加以后,如果这个类的源文件存在,会在文件编辑器的标记栏中显示被选择的方法的断点。
4在进入该方法的那一刻,在该方法任何代码执行之前,线程就被挂起。也可以将方法断点设置在方法退出时中断。
(2)条件断点
可以为断点设定条件,以便断点在被设定条件发生时使线程挂起。
为一个断点设定条件的步骤如下:
1找到需要设定条件的断点。
2右击,在弹出的菜单中选择【断点属性…】命令,将弹出如图4-41所示的对话框。
图4-41 断点属性
3在断点属性对话框中将“启用条件”复选框选中,在文本区域里输入条件表达式。如果希望每次条件成真时断点都会使线程挂起,那么就要在“暂挂时间”字段下选择“条件为‘true’”这一项;如果希望在根据条件判断的结果改变时才使线程挂起,就要选择“条件的值更改”这一项。
4设置完毕后,单击【确定】按钮完成条件断点的设定。
从图4-41上可以看出,还有一个“命中计数”的选项。“命中计数”适用于行断点、异常断点、观察点和方法断点。断点启用“命中计数”后,“命中计数”就开始工作。线程运行经过该断点n次后,线程就会被挂起,但是这个“命中计数”只能作用一次,除非它被再次启用或更改命中次数。
注意
n代表用户在“命中计数”中设置的具体数字,例如5。
(3)Java异常断点
通过使用异常断点,可以在抛出异常时挂起线程,可以在捕获异常的地方挂起线程,可以在未捕获异常的地方挂起线程,还可以在捕获和未捕获异常的地方都挂起线程。设置Java异常断点的步骤如下:
1在断点视图中的工具栏中单击【添加Java异常断点】按钮,在弹出的窗口中列出了所有的可用的异常,如图4-42所示。
图4-42 添加Java异常断点
还可以从工作台的菜单栏中选择【运行→添加Java异常断点…】命令,进入如图4-42所示的窗口。
2输入或从列表里选择一个希望捕获的异常。在下面的两个复选框中选择希望在什么地方挂起线程。最后单击【确定】按钮,完成Java异常断点的添加。
3.远程调试
Java调试器的客户机/服务器(C/S)设计允许用户在网络中的计算机上启动Java程序,并从运行平台的工作站调试该程序。
注意
要进行远程调试,就必须使用支持这个特性的JVM(Java虚拟机)。JDK1.4以后的版本都支持这个特性。
在进行远程调试之前,必须能够在调试模式下启动远程计算机上的程序,以便它能够与本地调试器建立连接。用于启动程序和链接调试器的特定技术是基于VM(虚拟机)的。
除了以上这些准备工作外,还需要使用“远程Java应用程序”启动配置。远程程序启动后,这个启动配置就会提供与应用程序建立的连接的信息。
下面就可以进行远程调试了,主要步骤如下:
1在Eclipse工作台的主菜单栏中选择【运行→调试…】命令,在弹出的配置窗口中双击“远程Java应用程序”,将新建一个远程Java应用程序(例如StringsDemo类),也可以右击“远程Java应用程序”,在弹出的菜单中选择【新建】命令。单击这个StringsDemo类,如图4-43所示。
图4-43 远程Java应用程序
2这个远程配置中有3个选项卡,分别是“连接”、“源”和“公共”。
在“连接”选项卡的“项目”字段中输入一个项目名作为启动的参数,也可单击【浏览】按钮选择。在“连接属性”的“主机”字段中输入Java程序正在其中运行的主机的IP地址或域名。在“端口”字段中输入远程VM接受连接的端口。“允许终止远程VM”复选框能确定是否在调试器中启用终止命令。
注意
一般情况下,端口号都是在远程VM启动时就确定好了的,如8000。
3单击【调试】按钮,程序开始尝试按照输入的地址和端口来连接VM,调试视图将会显示结果。如果无法连接远程的VM,就会出现如图4-44所示的错误。
图4-44 无法连接远程VM提示