有效地对软件进行交互式诊断的技术和工具
2008-01-05 08:36:21 来源:WEB开发网核心提示:通常,在运行 java 程序时,有效地对软件进行交互式诊断的技术和工具,必须使用 String[] 输入参数将参数传入,从 main() 方法运行程序,NextGen 编程语言是 Java 语言添加了一些语言功能的扩展,他还是 DrJava ? 一个为初学者设计的开放源代码的 Java IDE ? 的项目经理,但是假如
通常,在运行 java 程序时,必须使用 String[] 输入参数将参数传入,从 main() 方法运行程序。但是假如程序仍在调试中,那么,这可能会成为一项繁重的任务。本月,Eric Allen 讨论对程序中的表达式和语句进行交互式评价的优点,并且提供几个帮助您处理这一任务的 Java repl(“read-eval-PRint-loop”工具,“读取-评价-打印-循环”工具)。他还讨论交互式评价如何帮助构建 GUI 和探索新的 API。阅读本文后,您将理解在预调试(pre-debugged)程序中交互地诊断小错误的做法及原因,您将能够使用一些 Java 工具来方便您的工作。请单击本文顶部或底部的讨论在讨论论坛与作者及其他读者共享关于本文的心得。
多数程序都包含很多方法,这些方法分布在为数众多的类中。毫无疑问,从程序的 main 入口点测试所有这些方法,即使不是不可能的,也是很困难的。
这就是单元测试之所以有用的原因。许多程序员和软件设计人员(包括我自己)强调单元测试在编写健壮的的软件时是有用的。但是假如您想能够以一种交互性更好的方式访问程序中的各种元素时,则可能要折衷一下。
当确实要这样做时,为每个结果编写、编译并运行新的单元测试就会很快变成一件繁重的事情。我发现,当不能预知给予特定输入后程序将表现出什么行为时(例如:在 AI 程序中可能就会出现这种情况),尤其如此。
那么,该怎么办呢?
不要为小改动着急
为了作一个类比,请考虑用通常情况下进行编译的语言(例如:Java 或 C++)编程和用在更多情况下进行解释的语言(Python 或 Scheme)编程之间的差异。
在编译型语言中,每个编写/测试/调试循环都必须包含编译这一额外的步骤,这可能是一个单调乏味的经历,尤其是对于一些小改动而言。这可能会使我们得出结论说,解释型语言更流畅,因而也更易于修改。(这种灵活性是有代价的:解释型语言通常更少对代码执行静态检查,例如类型检查。)
正如有时候我们可能想对程序作个改动,但不必经历重编译的麻烦一样,我们也可能想检查程序中的一些元素,但不必例行公事般在套件中添加一个新的单元测试。当确实想这样做时,拥有传统上称为“读取-评价-打印-循环”(即 repl)的工具可能会有所帮助。
repl 是一个基于文本的工具,它以表达式作为输入,在特定程序的上下文中进行评端,然后显示结果。接着,它等待获得另一个表达式作为输入,然后重复这些操作。这样的工具源于类似 Lisp 的语言,但它们也能在更新的语言(例如:Python)中使用。
repl 在 Java 编程中的好处
这样的工具并非仅仅在这些语言中是有用的。Java 程序员也可以从使用 repl 中获得好处,不只是调试方面,在其它方面也可以。
构建 GUI
当组装一个 GUI 时,有许多组件需要布置和连接。当构造 GUI 时,您肯定会碰到以下这些事情:
组件之间将以不可见的方式相互作用。
在运行 GUI 之前写出其所有代码是相当费时的。
一旦您看到了 GUI 的实际视觉效果,不可避免地,您将会想更改 GUI 的某些方面。
这个问题的一种常见的“解决方案”是使用图形化的 GUI 构建工具,例如那些包含在 JBuilder、Forte 和其它 IDE 中的 GUI 构建工具。我个人不喜欢这种办法 ? 您很难知道这个工具会给您生成什么样的 Java 代码,您也不可能在修改所生成的代码时不冒丧失与 GUI 构建工具的兼容性的风险(事实上,有些 IDE 强行禁止您修改机器生成代码的任何部分)。
此外,许多这类 GUI 构建工具在生成 Java 代码时都使用专用 GUI 库,因而限制了 GUI 的兼容性。
我发现使用 repl 来构建 GUI 要轻易得多。我完全可以交互地定义每一个 GUI 组件,然后依次显示它。我能够马上修正任何不喜欢的东西。然后,我可以与之交互并将这些组件粘贴到程序中。
探索新 API
使用 Java 语言编程最大的优点之一是,有数量庞大的 API 可以使用,它们可以与一切事物 ? 从数据库到 Web 服务到电视 ? 对接。不过需要花些时间学习 API 的语义。
通常,Javadocs 不会对 API 的行为的每个方面都作出明确说明。对付这种窘境的办法是直接测试 API,使用 repl 可以使测试快得多 ? 只要输入一个方法调用看看其结果就行了!
一个额外的好处是,使用 repl 测试 API 还强化了大多数程序员的主要行为 ? 我们倾向于在实践中取得最好的学习效果。
Java 编程中可用的 repl
那么,假如 repl 有这么多优点,下一个问题显然是 Java 语言可以使用哪些 repl?
Jython
Jython(以前的名称是 JPython)是 Python 的 Java 编程语言实现(包含一个 repl)(经认证,是 100% 纯 Java 的)。实际上,它把 Python 编译成(有点复杂)Java 源代码或直接编译成字节码。
本着 Python 的精神,人们尝试了各种办法以提供 Java 和 Jython 之间的无缝互操作性。Jython 让您可以访问所有的 Java 标准库,就似乎您是自然地使用 Java 语言进行编程一样,您也可以访问现有的 Java 类文件。所以您不仅可以将 repl 用来与标准库一起工作,还可以与已经编译成字节码的您自己的 Java(或 Jython)类一起工作。
使用 Jython repl 时的一个重要注重事项是您在写 Python 表达式,而不是 Java 表达式。其积极的一面是您得到了 Python 在句法方面简明而又美丽的优点。
例如,假如我想构造一个新的散列表,这个表将 a 映射到 1、b 映射到 2,c 映射到 3。使用 Jython 我所要写的只是:
>>> h = {′a′:1, ′b′:2, ′c′:3}
解释器在每一个新的输入行前显示 >>>。
当探索新的 GUI 设计时,Jython 句法也有很多优点。举个例子来说,可以将 GUI 元素的各个域指定为构造函数的要害字参数,就像这样:
>>> from javax.swing import *
>>> f = JFrame(visible=1)
这个示例说明了 Jython 和 Java 语言的其它一些差异:
导入语句的句法有很大不同。
整型被用来取代了布尔型(1 是真,0 是假)。
这里是另一个示例,示例中 Jython 代码为您节省了一些输入,给 GUI 元素添加了动作侦听器(action listener)。通常,这样的侦听器通过使用命令模式(Command Pattern)被指定为匿名内部类的实例。在 Python(和其它许多“脚本”语言)中,这样的命令可以通过使用交互式函数定义更简洁地加以指定。例如,让我们在上述的交互式会话的基础上给 JButton 添加一个简单的动作侦听器:
>>> def listener(event):
... print ′thank you′
>>>
这是 Jython 中的函数定义的一个示例。为了让我们知道它什么时候需要一个语句以便继续进行,解释器在下一行打印省略号(代替脱字符)。这个函数只需要一个参数,并会将“thank you”打印到标准输出。我们可以将它用作动作侦听器,如下:
>>> panel = JPanel()
>>> panel.add(JButton(′press me′, actionPerformed=listener))
>>> f.getContentPane().add(panel)
>>> f.pack()
现在,我们将有一个显示在屏幕上的窗口,这个窗口有一个标有“press me”的按钮,按下这个按钮后将打印“thank you”到标准输出。想像一下,假如使用 Java 代码的话,这将需要多少语句啊。
当然,缺点也是有的。例如:
您失去了静态类型检查(尽管按理说静态检查在 repl 中没有多少价值)。
因为您输入到 repl 中的表达式不是 Java 代码,所以您无法在转换它们之前将表达式从 repl 中复制和粘贴到您的程序中。
当与 Java 代码一起使用 Jython 时,您得承担在脑海中同时处理两种语言的额外脑力负担(尽管有些人认为这样做很好玩)。
DynamicJava
Java 可以使用的另一个 repl 是 DynamicJava,一个真正基于 Java(呃,基本上是对的)的开放源代码的工具,它有一些不同之处:
repl 语言答应您不必在声明变量时指定变量的静态类型。
您不必在语句末尾添加一个分号。解释器也会返回(随意地)null 作为语句的评价结果。(假如语句根本不返回值,情况会好得多。)
不限制您从 repl 内访问对象的私有字段。
对于初级 Java 程序员,这些不同之处是很重要的,因为它们可能会使他们感到很迷惑。更有经验的程序员可能会乐于见到其中一些宽松的约束。无论如何,DynamicJava 都是一个健壮的、非常有用的软件产品(而且它是免费的,这是有帮助的)。
一个新的 Java IDE
在 Rice 大学的 JavaPLT 实验室(由 Robert Cartwright 教授领导),我们最近发布了 DrJava,一个新的、开放源代码的、用于 Java 语言的 GPL′d 开发环境,它包含了 DynamicJava repl 的一个洁净(cleaned-up)版本作为内置组件。我说“洁净”是因为我们已经隐藏了前面所描述的 DynamicJava 的某些更随意的功能。
DrJava 项目是一个极端编程项目,目的是开发供计算机科学低年级大学生教学之用的免费的、轻量级的 Java IDE。尽管这个 IDE 是为大学生设计的,但它的快速开发功能对所有级别的开发者都是有用的。DrJava 背后的理念是利用程序员的语言知识来提供强大的开发工具,这与某些尽力把程序员和实际代码隔离开来的 IDE 不同。
这个 IDE 的一些优异特征包括对注释和圆括号匹配的极其精确(比 Emacs 更精确)的突出显示,以及可单击的编译器错误的源代码突出显示。其界面包含几个可单击的选项卡:
Interactions 选项卡答应您与 DynamicJava repl 交互,创建新编译过的类的实例,测试新编译过的类。
Compiler Errors 选项卡答应您单击各种编译器错误,将光标移到编辑面板中出错的源代码的位置。
Console 选项卡显示所有发送到 System.out 和 System.err 的消息。
(这里是 DrJava 的一个屏幕截图。)
我们对这个 IDE 的经验是,交互作用窗格答应程序员轻易地执行复杂的开发和调试任务。跟在其它语言中所表明的一样,源代码编辑器和 repl 的结合构成强大的工具。
repl 总结
希望本部分已经指出并演示了一种主要工具,它能让您交互地对 Java 程序中的表达式和语句进行评价,而不陷入重编译的泥沼 ? 这种工具就是“读取-评价-打印-循环”即 repl 工具。我们还演示了 repl 如何体现它在构建 GUI 中的重要性,或者当您只是想快速地检查大量可以使用的 Java API 时,它又是如何体现它的重要性的。
参考资料
通过单击本文顶部或底部的讨论参加本文的讨论论坛。
Jython 2.1 是 Python 高级别的、动态的、面向对象的实现,它答应您在任何 Java 平台上运行 Python。(了解关于其源祖语言 Python 2.2 的更多信息。)
developerWorks linux 专区上的 Charming Python 专栏的这篇文章,“Inside JPython and Python for .NET”,快速地窥探了一下 JPython 的内幕。
另请访问 DynamicJava,一个 Java 源代码解释器。
别忘了下载 DrJava,并利用带有内置 repl 的 IDE 的强大功能。
阅读 Eric Allen 的 Diagnosing Java Code 专栏的所有文章。
请在 developerWorks Java 技术专区查找更多的 Java 参考资料。
关于作者
Eric Allen 从 Cornell 大学获得计算机科学和数学的学士学位,也是 Rice 大学 Java 编程语言小组的 PhD 研究生。在回 Rice 完成他的学位学习前,Eric 是 Cycorp 公司的主要 Java 软件开发者。他还在 JavaWorld 上主持了一个“Java 初学者”讨论论坛。他的研究涉及源代码和字节码级别上的 Java 语言语义模型和静态分析工具的开发。Eric 是针对 NextGen 编程语言的 Rice 的实验编译器的主要开发者,NextGen 编程语言是 Java 语言添加了一些语言功能的扩展,他还是 DrJava ? 一个为初学者设计的开放源代码的 Java IDE ? 的项目经理。请通过 eallen@cs.rice.edu 与 Eric 联系。
--摘自IBM网站
http://www-900.ibm.com/developerWorks/cn/java/j-diag/part22/index.sHtml
赞助商链接