诊断Java代码: 使用静态类型的理由

静态类型 ― 多数程序员喜欢它或憎恨它。支持者夸耀说静态类型让他们写出更干净更可靠的代码,没有它们则做不到这么好。批评者埋怨说静态类型增加了程序的复杂性。

是的,静态类型不是免费午餐;有时候,它们用起来很乏味。然而,如果我们主要关心的是使代码没有错误,那么,总的说来,Java 编程还是拥有并使用静态类型好些。为什么?静态类型检查:

通过早期错误检测,提高健壮性

通过在最佳的时候作所需的检查,提高性能

弥补单元测试的缺点

我们来更仔细地分析这些原因,并看一看静态类型检查和结对编程(pair programming)混用。

通过早期检测,提高健壮性

静态类型检查能提高程序健壮性。为什么?因为它有助于尽快找到错误 ― 在程序运行前。这里的逻辑舍此无它。错误越早被发现,问题诊断起来就越容易,也就只有越少的数据会被错误的计算毁坏。

在程序运行前就找到并诊断错误是理想状态。这个优点使静态类型检查成为编程语言设计中的伟大成功,因为它是少数几种能在程序运行前自动检测程序中的错误的方法,而且它可在可接受的时间内完成这个任务。“可接受的时间”意思是与程序长度呈线性关系的时间(有一个很小的常数系数),而不是其它形式自动检查所要求的呈立方甚至呈指数关系的时间(许多甚至根本不保证完成)。

是的,类型系统越强大,编起程序来就越容易(且系统将检测越多的错误)。我不否认 Java 简单的类型系统留有很多缺憾;它经常阻碍我们,迫使我们用强制转型来绕过。但这种状况正在慢慢改善。

Sun JSR14 编译器在语言中增加了形式有限的泛型(也称为 参数化)类型;我们相信它迟早会被加入该语言,因为它目前在 Java 社区过程中得到了坚定的支持。更高级的语言扩展(例如 NextGen)承诺在 JSR14 提供的增加的表达力上更上一层楼。那是好事,因为在很多环境下 NextGen 都有助于减少甚至在 JSR14 中也是需要的一些增加的复杂性。请参阅 参考资料找到关于这个问题的更多信息。(除了 JSR14 链接,还有些关于 参数的多态性的文章。)

然而,静态类型检查的好处不仅仅是健壮性。它还能保护您的程序的性能。

通过减少所需的检查,提高性能

在安全的语言中(“安全”的意思是指不允许我们破坏它自己的抽象的语言),对传给方法的参数的类型作各种检查是必需的并一定得完成,对被存取的域的类型的检查也是必需的并一定得完成。如果这些检查不是静态地完成,那么它们必须在运行时完成。

进行这些所需的检查是费时的,在运行时进行这些检查的语言,其性能会相应受损。当不变量被静态地检查时,我们不必在运行时检查它,从而加快程序运行。所以,静态类型检查使我们得以写出更健壮更高效的代码。

传统上认为编译时静态类型检查是低效的。对于用 C/C++ 之类语言写的大程序来说,在文件间链接各种类型引用是很费时的,因为每次编译时,各种文件必须被合在一起生成一个大的可执行文件。但是 Java 语言完全避免了这个问题,因为类是分开编译的,在需要时装入到 JVM。没有必要把所有的引用文件链接成一个可执行文件 ― 所以在编译时没有相应的放慢。

现在,我们对那些声称静态类型在单元测试环境下是不必要的人说些什么呢?

时间: 2024-10-14 13:19:27

诊断Java代码: 使用静态类型的理由的相关文章

诊断Java代码

诊断Java代码: Broken Dispatch错误模式 诊断Java代码: Double Descent错误模式 诊断Java代码: Impostor Type错误模式 诊断Java代码: Java编程中的断言和时态逻辑 诊断Java代码: Liar View错误模式 诊断Java代码: Repl提供交互式评价 诊断Java代码: 单元测试与自动化代码分析协同工作 诊断Java代码: 将时态逻辑用于错误模式 诊断Java代码: 进行记录器测试以正确调用方法 诊断Java代码: 空标志错误模式

诊断Java代码: Impostor Type错误模式

当使用字段中特殊的标记来区别对象类型时,可能会产生标记对相关数据误贴标签的错误 ― 通称为 Impostor Type 错误模式.在诊断 Java 代码的这一部分中,Eric Allen 对这个错误的症状和起因进行了分析,详细说明了预防错误发生的方法,并讨论了一种吸引人的混合实现方法,这种方法不使用 impostor type,但最后,还是有很多相同的缺点产生.请在 讨论论坛与作者及其他读者分享您对本文的看法. 程序中除了最无关紧要的部分外都要对某些数据类型进行操作.静态类型系统提供了一种方法,

诊断Java代码: 进行记录器测试以正确调用方法

用 JUnit进行单元测试是一个功能强大的方法,它可以确保您的代码基础的完整性,但是一些不变量比其他(方法调用序列是其中一种)更难测试.在诊断Java 代码这一部分,Eric Allen描述了怎样在您的单元测试中使用记录器(一种特殊的侦听器),来确保一个方法调用序列按恰当的顺序发生.请点击文章顶部和底部的 讨论,与作者和其他读者在论坛上分享您关于本文的看法. 随着时间的推移,当系统开发人员,维护人员甚至是系统详细说明改变时,JUnit 框架提供一个很好的方法来改善系统的坚固性.通过测试,您可以检

诊断Java代码: 设计可扩展的应用程序,第2部分

玻璃箱可扩展性是指这样一种方式:软件系统可在源代码可以查看而不可以修改时被扩展 ― 它是黑箱设计(在这里构建扩展时,不查看原始代码)和开放箱设计(扩展代码直接写入到基础代码)的折衷.因为新的扩展直接建立在原始代码基础上,但不改动原始代码,所以,玻璃箱设计或许是扩展一个软件系统最有效.最安全的方法.在 诊断 Java 代码的这一部分中,Eric Allen 详述了上个月谈及的玻璃箱可扩展性主题.读完本文后,您将知道什么时候使用玻璃箱,并将获得一些如何实现它的提示. 随着信息处理任务(和与之相关的成

诊断Java代码: 设计可扩展应用程序,第3部分

对应于我们上一篇" 诊断 Java 代码"中所讨论的透明盒可扩展性,黑盒可扩展性是指,在源代码既不能查看也不能修改时,可以扩展软件系统的方法.通常通过系统配置或使用特定于应用程序的脚本语言来进行这样的扩展.在本专题中,Eric Allen 讨论了何时设计黑盒可 扩展性的系统是有意义的,并提供了如何有效地实现这一设计的一些想法.阅读了本文后,您将知道何时使用黑盒并掌握如何实现它的一些技巧. 我已在以前的文章中谈到了代码重用设计策略的重要性(主要是因为各种信息处理任务的差异和相应费用的增加

诊断Java代码:孤线程(Orphaned Thread)错误模式

在多线程代码中,使用驱动其它线程所负责的动作的单个主线程是常见的.这个主线程发送消息,通常是通过把它们放到一个队列中,然后其它线程处理这些消息.但是如果主线程抛出一个异常,那么剩余的线程会继续运行,等待更多输入到该队列,导致程序冻结.在诊断 Java 代码的这一部分中,专职 Java 开发者兼兼职捉虫者 Eric Allen 讨论检测.修复和避免这一错误模式. 用多线程编写代码对程序员大有好处.多线程能使编程(和程序)进行得快得多,而且代码能有效得多地使用资源.然而,跟生活中的很多事情一样,多线

诊断Java代码: 悬挂复合错误类型

空指针到处都有! 在一个 Java 程序员所能遇到的所有异常中,空指针异常属于最恐怖的,这是因为:它是程序能给出的信息最少的异常.例如,不像一个类转型异常,空指针异常不给出它所需要的内容的任何信息,只有一个空指针.此外,它并不指出在代码的何处这个空指针被赋值.在许多空指针异常中,真正的错误出现在变量被赋为空值的地方.为了发现错误,我们必须通过控制流跟踪,以发现变量在哪里被赋值,并确定是否这么做是不正确的.当赋值出现在包中,而不是出现在发生报错的地方时,进程会被明显地破坏. 许多 Java 开发人

诊断Java代码: Broken Dispatch错误模式

整体和部分 还记得这条谚语吗,"整体大于部分之和"?如果把一个个独立的事件组合成一个相互作用的整体,产生的结果会比单个个体的作用之和要大得多. 程序也是一样的道理.随着一个个新方法被添加到程序中,整个程序可能的控制流程迅速增加.对于大型程序而言,很快局面就会无法控制了.就象是一个荒谬而又不可思议的戏法,有时您得到的最终结果并不是您所期望的方向 ― 这同您在重载方法或者覆盖方法时遇到的情况有些类似. Broken Dispatch 错误模式 面向对象语言的最强大的特性之一就是继承多态性.

诊断 Java 代码:设计轻松的代码维护

设计 本月,Eric Allen 解释了在使代码更易于维护的同时,避免和控制无理由的变化怎么会是保持代码健壮性的关键.他集中讨论了诸如函数样式代码编写之类的概念,以及标记字段.方法和类的方法来处理并防止可变性.Eric 还解释了本任务中单元测试和重构的角色,并提供了协助实现重构的两个工具.在相关论坛中与作者和其他读者分享您对本文的看法.(您也可以单击本文顶部或底部的"讨论",访问该论坛.)有效调试源自良好的编程.设计易于维护的程序是程序员面临的最困难挑战之一,其部分原因在于程序通常并不