将接口名与类和包的名字区分开来。我喜欢这种命名约定,仅仅只是因为它使类的图表,有时也叫对象模型,变得易读。这种方法的一个主要的缺点是一些现有的接口,如 Runnable,未采用此种方法。这种接口命名约定在 Microsoft 的 COM/DCOM 体系结构中也很流行。
注释接口
以下的信息应写在文档注释中紧靠接口定义的前面:
1. 目的。在其他开发者应用一个接口之前,他们需要理解接口封装的
概念。换句话说,他们需要了解接口的目的。一个好的检测是否有必要定义一个接口的方法是你是否可以很容易地说明它的目的。 如果说明起来有困难,很可能从一开始起就不需要这个接口。在 Java 中接口的概念较新,所以人们对如何正确使用它们还不是很有经验,常常滥用它们。
2.它应如何被使用以及如何不被使用。开发者需要了解接口应如何使用
以及如何不被使用 [COA97]。
因为成员函数的标识在接口中定义,所以对于每个成员函数的标识
应遵循第二章中所讨论的注释约定。
包的标准
包的一些重要标准基于:
? 命名约定 ? 注释约定
命名包
关于包的命名有几条规则。按顺序来说,这些规则是:
1.标识符用点号分隔开来。为了使包的名字更易读,Sun 公司建议包名
中的标识符用点号来分隔。例如,包名 java.awt 含有两个标识符 java 和 awt。
2.Sun 公司的标准 java 分配包用标识符 .java 开头。Sun 保有这种
权利,使得无论你的 Java 开发环境的零售商是怎样的,标准 java 包的命名始终一致。
3.局部包的名字中的第一个标识符不能都是大写。所谓局部包是指那些
在你的机构内部使用,不会应用到其他机构中去的包。这样的包的
名字的例子有 persistence.mapping.relational 和
interface.screens。 4. 全局包的名字用你的机构的 Internet 保留域名开头。一个要应用到
多个机构的包应包含创建机构的域名,并且最高层的域名类型要大写。例如,要应用前面的包,它们应被命名为
com.rational.www.persistence.mapping.relational com.rational.www.interface.screens。0
和
注释包
应保有一个或者多个外部文档以说明你的机构所创建的包的用途。对于每个包,应说明:
1.包的基本原理。其他开发者需要了解一个包是用来做什么的,这样他
们才能判断是否可以用它,如果是一个共享包,他们可以判断是否需要改进或是扩展它。 2.包中的类。在包中要包含一个类和接口的列表,每个类或接口用简短
的一行文字来说明,以便让其他的开发者了解这个包中含有什么。
技巧:生成一个以包名命名的 HTML 文件,将它放到包的适当的目录中去。这个文件应具有后缀 .html。
编译单元标准
编译单元的标准和指南基于:
? 命名约定 ? 注释约定
命名编译单元
编译单元,在这个情况下是一个源码文件,应被赋予文件内定义的主要的类或接口的名字。用与包或类相同的名字命名文件,大小写也应相同。扩展名 .java 应作为文件名的后缀。 示例:
Customer.java Singleton.java SavingsAccount.java
注释编译单元
虽然应努力使一个文件中只包含一个类或接口,但是有时在一个文件中定义数个类(或者接口)也可理解。一般的经验规则是,如果类 B 的唯一用途是封装只被类 A 需要的功能,那么可以理解类 B 出现在与类 A 相同的源码文件中。结果下面的文档约定应用于一个源码文件,而不具体到类:
1.对于有几个类的文件,列出每一个类。如果一个文件包含多个类,则
应给出一个类的列表,并且简要地说明每个类。 2.文件名和/或标识信息。文件名应包含在它的顶端。好处是如果代码被
打印出来了,你会知道源码文件是什么。 3. 版权信息。若可能,应说明文件的所有版权信息。通常的做法是说明
版权的年份和版权持有个人/机构的名字。注意:代码的作者可能不
是版权持有者。
错误处理和异常
通常的思想是只对错误采用异常处理:逻辑和编程错误,设置错误,被破坏的数据,资源耗尽,等等。通常的法则是系统在正常状态下以及无重载和硬件失效状态下,不应产生任何异常。
用异常处理逻辑和编程错误,设置错误,被破坏的数据,资源耗尽。尽早采用适当的日志机制来报告异常,包括在异常发生的时刻。 最小化从一个给定的抽象类中导出的异常的个数。
在大型系统中,不得不在每一级处理大量的异常使得代码难于理解和维护。有时,异常阻碍了正常的处理。 有以下几种方式最小化异常的数目:
? 仅导出几个异常,但提供“diagnosis”原语,用以查询
错误抽象类或对象,以得到有关产生出的问题本质的更多信息。
? 在对象中加入“exceptional”语句,并且提供用来明确
检查对象可用性的原语。
对于经常发生的可预计事件不要采用异常。
用异常来表达并非一定是错误的状态有几个不便之处:
? 它易混淆。
? 它通常在控制流中强制性地产生一些中断,而这些中断
更难理解和维护。
? 它使得代码调试起来更令人痛苦,因为大多数源码级的
调试器在缺省值状态下标志出所有的异常。
例如,不要将异常以某种额外值的形式由函数返回(象查询中的 Value_Not_Found)。使用一个含有“out”参数的进程,或者引入一个意思为 Not_Found 的特殊值,或者在一个含有区别量 Not_Found 的记录中包装一个返回类型。
不要使用异常实现控制结构。
这是前面规则的一个特例:异常不应作为“goto”语句的一种形式来使用。
确保状态码有一个正确值。
当用一个子程序返回的状态码作为一个“out”参数时,一定要确保“out”参数被赋了值,这可以通过将赋值语句作为子程序体的第一个可执行语句来实现。系统化地使所有状态的缺省值为 “success” 或是 failure”。考虑子程序的所有可能出口,包括异常处理。
在本地进行安全性检查,不要指望你的客户会去做这件事。
也就是说,如果一个子程序被给予错误的输入时可能给出错误的输出,则应在子程序中通过控制方式加入检测和报告非法输入的代码。不要依赖于注释来告诉客户输入正确值。如果不检测无效参数,注定早晚有一天,那条注释会被忽略,导致难以调试的错误。
各种标准和版本
这一章说明几个重要的标准/指南,但因为它们涉及很广,所以足以单独列出一章。
复用
任何你从外部源所购买/复用的 Java 类库或者包应是 100% 纯粹的 Java 语言 [SUN97]。 通过强调这一标准,确保了你所用的东西将在你想设置它的所有平台上工作。你可以从各种途径获得 Java 的类、包或者 Applets,或是第三方的专门开发 Java 库的开发公司,或是你的机构中的另一个部门或项目组。
导入类
在说明类名时,import 语句允许使用通配符。例如, import java.awt.* 语句
一次性地引入了包 java.awt 中的所有类。 实际上,这并不完全正确。实际情况是每一个所使用的取自于 java.awt 包中的类,在编译时被引入代码,而其中未使用的类不被引入。虽然这听起来象是一个好的特点,但是它却降低了代码的可读性。一个更好的方法是完全限制代码所使用的类的名字 [LAF97],[VIS96]。一个较好的导入类的方法如下面的例子所示:
import java.awt.Color; import java.awt.Button; import java.awt.Container;
优化 Java 代码
优化 Java 代码是程序员最后而不是最先应考虑的事。将优化放到最后是因为只要优化那些需要优化的代码。代码的一小部分常常占用了处理时间的大部分,这样的代码就应该优化。缺乏经验的程序员会犯的一个经典性的错误是,想优化他们所有的代码,甚至那些运行起来已经很快的代码。
不要浪费时间去优化那些没人会在意的代码!
当优化代码时应该寻找什么?[KOE97] 指出最重要的因素是固定费用和大输入量时的性能。理由很简单:固定费用决定了程序在小输入量时的运行速度,算法决定了大输入量时的运行速度。他的基本规则是,一个程序若在小输入量和大输入量时都运行得很好,那么在中等输入量的情况下很可能也会运行得很好。