`

JAVA编程规范

    博客分类:
  • Java
阅读更多

作者:李小敏 本文选自:IBM DW中国 2002年08月21日

作者按:所有的程序开发手册都包含了各种规则。一些习惯自由程序人员可能对这些规则很不适应,但是在多个开发人员共同写作的情况下,这些规则是必需的。这不仅仅是为了开发效率来考虑,而且也是为了后期维护考虑。

定义这个规范的目的是让项目中所有的文档都看起来像一个人写的,增加可读性,减少项目组中因为换人而带来的损失。(这些规范并不是一定要绝对遵守,但是一定要让程序有良好的可读性) 


Package 的命名 
Package 的名字应该都是由一个小写单词组成。 
Class 的命名 
Class 的名字必须由大写字母开头而其他字母都小写的单词组成 
Class 变量的命名 
变量的名字必须用一个小写字母开头。后面的单词用大写字母开头。 
Static Final 变量的命名 
Static Final 变量的名字应该都大写,并且指出完整含义。 
参数的命名 
参数的名字必须和变量的命名规范一致。 
数组的命名 
数组应该总是用下面的方式来命名: 

byte[] buffer;


而不是: 

byte buffer[];



方法的参数 
使用有意义的参数命名,如果可能的话,使用和要赋值的字段一样的名字: 

SetCounter(int size){
this.size = size;
}




Java 文件样式 
所有的 Java(*.java) 文件都必须遵守如下的样式规则 


版权信息 
版权信息必须在 java 文件的开头,比如: 

/**
* Copyright ? 2000 Shanghai XXX Co. Ltd.
* All right reserved.
*/


其他不需要出现在 javadoc 的信息也可以包含在这里。


Package/Imports 
package 行要在 import 行之前,import 中标准的包名要在本地的包名之前,而且按照字母顺序排列。如果 import 行中包含了同一个包中的不同子目录,则应该用 * 来处理。 

package hotlava.net.stats;

import java.io.*;
import java.util.Observable;
import hotlava.util.Application;


这里 java.io.* 使用来代替InputStream and OutputStream 的。


Class 
接下来的是类的注释,一般是用来解释类的。 

/**
* A class representing a set of packet and byte counters
* It is observable to allow it to be watched, but only
* reports changes when the current set is complete
*/


接下来是类定义,包含了在不同的行的 extends 和 implements 

public class CounterSet
extends Observable
implements Cloneable



Class Fields 
接下来是类的成员变量: 

/**
* Packet counters
*/
protected int[] packets;


public 的成员变量必须生成文档(JavaDoc)。proceted、private和 package 定义的成员变量如果名字含义明确的话,可以没有注释。


存取方法 
接下来是类变量的存取的方法。它只是简单的用来将类的变量赋值获取值的话,可以简单的写在一行上。 

/**
* Get the counters
* @return an array containing the statistical data. This array has been
* freshly allocated and can be modified by the caller.
*/
public int[] getPackets() { return copyArray(packets, offset); }
public int[] getBytes() { return copyArray(bytes, offset); }

public int[] getPackets() { return packets; }
public void setPackets(int[] packets) { this.packets = packets; }
其它的方法不要写在一行上
构造函数 
接下来是构造函数,它应该用递增的方式写(比如:参数多的写在后面)。 
访问类型 ("public", "private" 等.) 和 任何 "static", "final" 或 "synchronized" 应该在一行中,并且方法和参数另写一行,这样可以使方法和参数更易读。 

public
CounterSet(int size){
this.size = size;
}



克隆方法 
如果这个类是可以被克隆的,那么下一步就是 clone 方法: 

public
Object clone() {
try {
CounterSet obj = (CounterSet)super.clone();
obj.packets = (int[])packets.clone();
obj.size = size;
return obj;
}catch(CloneNotSupportedException e) {
throw new InternalError("Unexpected CloneNotSUpportedException: " + e.getMessage());
}
}



类方法 
下面开始写类的方法: 

/**
* Set the packet counters
* (such as when restoring from a database)
*/
protected final
void setArray(int[] r1, int[] r2, int[] r3, int[] r4)
throws IllegalArgumentException
{
//
// Ensure the arrays are of equal size
//
if (r1.length != r2.length || r1.length != r3.length || r1.length != r4.length)
throw new IllegalArgumentException("Arrays must be of the same size");
System.arraycopy(r1, 0, r3, 0, r1.length);
System.arraycopy(r2, 0, r4, 0, r1.length);
}




toString 方法 
无论如何,每一个类都应该定义 toString 方法: 

public
String toString() {
String retval = "CounterSet: ";
for (int i = 0; i < data.length(); i++) {
retval += data.bytes.toString();
retval += data.packets.toString();
}
return retval;
}
}



main 方法 
如果main(String[]) 方法已经定义了, 那么它应该写在类的底部. 

代码编写格式 


代码样式 
代码应该用 unix 的格式,而不是 windows 的(比如:回车变成回车+换行) 
文档化 
必须用 javadoc 来为类生成文档。不仅因为它是标准,这也是被各种 java 编译器都认可的方法。使用 @author 标记是不被推荐的,因为代码不应该是被个人拥有的。 
缩进 
缩进应该是每行2个空格. 不要在源文件中保存Tab字符. 在使用不同的源代码管理工具时Tab字符将因为用户设置的不同而扩展为不同的宽度. 
如果你使用 UltrEdit 作为你的 Java 源代码编辑器的话,你可以通过如下操作来禁止保存Tab字符, 方法是通过 UltrEdit中先设定 Tab 使用的长度室2个空格,然后用 Format|Tabs to Spaces 菜单将 Tab 转换为空格。 
页宽 
页宽应该设置为80字符. 源代码一般不会超过这个宽度, 并导致无法完整显示, 但这一设置也可以灵活调整. 在任何情况下, 超长的语句应该在一个逗号或者一个操作符后折行. 一条语句折行后, 应该比原来的语句再缩进2个字符. 
{} 对 
{} 中的语句应该单独作为一行. 例如, 下面的第1行是错误的, 第2行是正确的: 

if (i>0) { i ++ }; // 错误, { 和 } 在同一行 

if (i>0) { 
i ++ 
}; // 正确, { 单独作为一行 


} 语句永远单独作为一行. 


如果 } 语句应该缩进到与其相对应的 { 那一行相对齐的位置。


括号 
左括号和后一个字符之间不应该出现空格, 同样, 右括号和前一个字符之间也不应该出现空格. 下面的例子说明括号和空格的错误及正确使用: 

CallProc( AParameter ); // 错误 
CallProc(AParameter); // 正确 

不要在语句中使用无意义的括号. 括号只应该为达到某种目的而出现在源代码中。下面的例子说明错误和正确的用法: 

if ((I) = 42) { // 错误 - 括号毫无意义 
if (I == 42) or (J == 42) then // 正确 - 的确需要括号 

程序编写规范 


exit() 
exit 除了在 main 中可以被调用外,其他的地方不应该调用。因为这样做不给任何代码代码机会来截获退出。一个类似后台服务地程序不应该因为某一个库模块决定了要退出就退出。 
异常 
申明的错误应该抛出一个RuntimeException或者派生的异常。 
顶层的main()函数应该截获所有的异常,并且打印(或者记录在日志中)在屏幕上。 
垃圾收集 
JAVA使用成熟的后台垃圾收集技术来代替引用计数。但是这样会导致一个问题:你必须在使用完对象的实例以后进行清场工作。比如一个prel的程序员可能这么写: 

...
{
FileOutputStream fos = new FileOutputStream(projectFile);
project.save(fos, "IDE Project File"); 
}
...


除非输出流一出作用域就关闭,非引用计数的程序语言,比如JAVA,是不能自动完成变量的清场工作的。必须象下面一样写: 

FileOutputStream fos = new FileOutputStream(projectFile);
project.save(fos, "IDE Project File"); 
fos.close();



Clone 
下面是一种有用的方法: 

implements Cloneable

public
Object clone()
{
try {
ThisClass obj = (ThisClass)super.clone();
obj.field1 = (int[])field1.clone();
obj.field2 = field2;
return obj;
} catch(CloneNotSupportedException e) {
throw new InternalError("Unexpected CloneNotSUpportedException: " + e.getMessage());
}
}



final 类 
绝对不要因为性能的原因将类定义为 final 的(除非程序的框架要求) 
如果一个类还没有准备好被继承,最好在类文档中注明,而不要将她定义为 final 的。这是因为没有人可以保证会不会由于什么原因需要继承她。 
访问类的成员变量 
大部分的类成员变量应该定义为 protected 的来防止继承类使用他们。 
注意,要用"int[] packets",而不是"int packets[]",后一种永远也不要用。 

public void setPackets(int[] packets) { this.packets = packets; }

CounterSet(int size)
{
this.size = size;
}
-------------------------------------------------------------------------------------------------------------------------------

设计类和方法
==================
创建具有很强内聚力的类
方法的重要性往往比类的重要性更容易理解,方法是指执行一个统一函数的一段代码。类常被错误的视为是一个仅仅用于存放方法的容器。有些开发人员甚至把这种思路作了进一步的发挥,将他们的所有方法放入单个类之中。 之所以不能正确的认识类的功能,原因之一是类的实现实际上并不影响程序的执行。当一个工程被编译时,如果所有方法都放在单个类中或者放在几十个类中,这没有任何关系。虽然类的数量对代码的执行并无太大的影响,但是当创建便于调试和维护的代码时,类的数量有时会带来很大的影响。
类应该用来将相关的方法组织在一起。 当类包含一组紧密关联的方法时,该类可以说具有强大的内聚力。当类包含许多互不相关的方法时,该类便具有较弱的内聚力。应该努力创建内聚力比较强的类。 大多数工程都包含许多并不十分适合与其他方法组合在一起的方法。在这种情况下,可以为这些不合群的方法创建一个综合性收容类。
创建类时,应知道“模块化”这个术语的含义是什么。类的基本目的是创建相当独立的程序单元。
创建松散连接和高度专用的方法
1) 所有方法都执行专门的任务
每个方法都应执行一项特定的任务,它应出色的完成这项任务。应避免创建执行许多不同任务的方法。 创建专用方法有许多好处。首先调试将变得更加容易。
2) 尽量使方法成为自成一体的独立方法
当一个方法依赖于其他方法的调用时,称为与其他方法紧密连接的方法。紧密连接的方法会使调试和修改变得比较困难,因为它牵涉到更多的因素。松散连接的方法优于紧密连接的方法,但你不可能使每个方法都成为独立的方法。
若要使方法具备较强的独立性,方法之一是尽量减少类变量。 创建方法时,设法将每个方法视为一个黑箱,其他例程不应要求了解该方法的内部工作情况,该方法也不应要求了解它外面的工程情况。这就是为什么你的方法应依靠参数而不应依靠全局变量的原因。
3) 创建专用方法时,请考虑下列指导原则:
(1) 将复杂进程放入专用方法。如果应用程序使用复杂的数学公式,请考虑将每个公式放入它自己的方法中。这样使用这些公式的其他方法就不包含用于该公式的实际代码。这样也可以更容易发现与公式相关的问题。
(2) 将数据输入/输出(I/O)放入专用方法。
(3) 将专用方法中可能要修改的代码隔离。如果你知道某个进程经常变更,请将这个多变的代码放入专用方法,以便以后可以更容易的进行修改,并减少无意中给其他进程带来问题的可能性。
(4) 将业务规则封装在专用方法中。业务规则常属于要修改的代码类别,应与应用程序的其余部分隔开。其他方法不应知道业务规则,只有要调用的方法才使用这些规则。
4) 设计类和方法时,要达到下列目的:
1) 创建更加容易调试和维护的方法
2) 创建具有强大内聚力的类
3) 创建高度专用的方法
4) 创建松散连接的方法
5) 尽量使方法具有独立性
6) 提高方法的扇入性
7) 降低方法的扇出性



编程原则
==================
为方法和类赋予表义性强的名字
为了使代码更加容易理解,最容易的方法之一是为你的方法赋予表义性强的名字。函数名DoIt、GetIt的可读性很难与CalculateSalesTax、 RetrieveUserID相比。 由缩写方法名组成的代码很难理解和维护,没有理由再这样做了。 给方法正确的命名,可使程序工程的调试和维护工作大大的改观。请认真对待方法命名的工作,不要为了减少键入操作量而降低方法的可理解度。 实际应用举例:
1) 给方法命名时应大小写字母混合使用。如果句子全使用大写字母,那么阅读起来就非常困难,而大小写字母混合使用的句子,阅读起来就很容易。
2) 定义方法名时不要使用缩写。如果你认为应用程序中的某些工程应使用缩写,那么请将这些情况加上注释,并确保每个人在所有时间内都使用这些缩写。决不要在某些方法中对某些单词进行缩写,而在别的方法中却不使用缩写。
为每个方法赋予单个退出点
创建方法时,始终都应显式地定义它的作用域
1) 如果你真的想创建一个公用方法,请向代码阅读者说明这一点。
2) 通过为每个方法赋予一个明确定义的作用域,可以减少代码阅读者需要投入的工作量。应确保你为方法赋予最有意义的作用域。如果一个方法只被同一类中的另一个方法调用,那么请将它创建成私有方法。如果该方法是从多个类中的多个方法中调用,请将该说明为公用方法。
用参数在方法之间传递数据
应尽量避免使用类变量。一般来说,变量的作用域越小越好。为了减少类变量,方法之一是将数据作为参数在不同方法之间传递,而不是让方法共享类变量。
1) 为每个参数指定数据类型。
2) 始终要对数进行检验,决不要假设你得数据没有问题。程序员常犯的一个错误是在编写方法时假设数据没有问题。在初始编程阶段,当编写调用方法时,这样的假设并无大碍。这时你完全能够知道什么是参数的许可值,并按要求提供这些值。但如果你不对参数的数据进行检验,那么下列情况就会给你带来很大麻烦:另外某个人创建了一个调用方法,但此人不知道允许的值;你在晚些时候添加了新的调用方法,并错误的传递了坏数据。



命名约定
==================
变量的定义
变量的定义应该遵循匈牙利命名法,它使用3字符前缀来表示数据类型,3个字符的前缀必须小写,前缀后面是由表意性强的一个单词或多个单词组成的名字,而且每个单词的首写字母大写,其它字母小写,这样保证了对变量名能够进行正确的断句。 这样,在一个变量名就可以反映出变量类型和变量所存储的值的意义两方面内容,这使得代码语句可读性强、更加容易理解。
包、类及方法命名
1) 包
全部小写。 标识符用点号分隔开来。为了使包的名字更易读,Sun 公司建议包名中的标识符用点号来分隔。
Sun 公司的标准 java 分配包用标识符 .java 开头。
全局包的名字用你的机构的 Internet 保留域名开头 。
局部包: interface.screens
全局包: com.rational.www. interface.screens
2) 类,接口
类的名字应该使用名词。
每个单词第一个字母应该大写。
避免使用单词的缩写,除非它的缩写已经广为人知,如HTTP。
Class Hello ;
Class HelloWorld ;
Interface Apple ;
3) 方法
第一个单词一般是动词。
第一个字母是小些,但是中间单词的第一个字母是大写。
如果方法返回一个成员变量的值,方法名一般为get+成员变量名,如若返回的值是bool变量,一般以is作为前缀。
如果方法修改一个成员变量的值,方法名一般为:set + 成员变量名。
getName(); setName(); isFirst();
4) 变量
第一个字母小写,中间单词的第一个字母大写。
不要用_或&作为第一个字母。
尽量使用短而且具有意义的单词。
单字符的变量名一般只用于生命期非常短暂的变量。i,j,k,m,n一般用于integers;c,d,e一般用于characters。
如果变量是集合,则变量名应用复数。
命名组件采用匈牙利命名法,所有前缀均应遵循同一个组件名称缩写列表。
String myName; int[] students; int i; int n; char c; btNew; (bt是Button的缩写)
5) 常量
所有常量名均全部大写,单词间以‘_’隔开。 int MAX_NUM;
6) 其它
开发人员如果遇到上述表格中未列举的类型,请书面通知相关管理人员,由管理人员集中更新列表内容,不得擅自启用未经确定的新变量前缀。




MVC规范
==================
分层
在MVC的设计模式中,要求在Application开发中你把商业逻辑,界面显示,数据分离。也就是分别在Model,View,Controller实现:数据,控制(商业逻辑)显示(页面显示)。
规则
1) 用户的所有请求统一由控制器截获
2) 控制器根据请求种类,调用不同的业务对象(业务bean),根据业务对象的返回值,来决定该把哪个页面相应给用户
3) 在jsp中,不会出现任何业务代码/数据库操作。可以有实例化bean的操作,或者从session、数据bean中取得数据
4) 在作为控制器的servlet中不会出现网页内容、业务代码、数据库操作。可以有接受request值、实例化bean、调用bean的方法、页面转移
5) 数据bean对应数据库中某张表里的一条记录,这张表中的所有列都应该成为数据bean的私有属性
6) 业务bean在Controller(servlet)中实例化
7) 数据bean在业务bean或Controller中实例化



其它规范
==================
Java文件样式
   所有的 Java(*.java) 文件都必须遵守如下的样式规则
   1) 版权信息
   版权信息必须在 java 文件的开头,比如:
   /**
   * Copyright &reg; 2000 Shanghai XXX Co. Ltd.
   * All right reserved.
   */
   其他不需要出现在 javadoc 的信息也可以包含在这里。
   2) Package/Imports
package 行要在 import 行之前,import 中标准的包名要在本地的包名之前,而且按照字母顺序排列。如果 import 行中包含了同一个包中的不同子目录,则应该用 * 来处理。
   package hotlava.net.stats;
   import java.io.*;
   import java.util.Observable;
   import hotlava.util.Application;
   这里 java.io.* 使用来代替InputStream and OutputStream 的。
   3) Class
   (1) 类的注释
接下来的是类的注释,一般是用来解释类的。
   /**
   * A class representing a set of packet and byte counters
   * It is observable to allow it to be watched, but only
   * reports changes when the current set is complete
   */
   (2) 类定义
(3) 类的成员变量
   接下来是类的成员变量:
   /**
   * Packet counters
   */
   protected int[] packets;
   public 的成员变量必须生成文档(JavaDoc)。
proceted、private和 package 定义的成员变量如果名字含义明确的话,可以没有注释。
(4) 构造函数
   接下来是构造函数,它应该用递增的方式写(比如:参数多的写在后面)。
   (5) 类方法
   下面开始写类的方法:
   /**
    * Set the packet counters
    * (such as when restoring from a database)
   */
   protected final
    void setArray(int[] r1, int[] r2, int[] r3, int[] r4)
    throws IllegalArgumentException
    {
    //
    // Ensure the arrays are of equal size
    //
    if (r1.length != r2.length || r1.length != r3.length || r1.length != r4.length)
   throw new IllegalArgumentException("Arrays must be of the same size");
   System.arraycopy(r1, 0, r3, 0, r1.length);
   System.arraycopy(r2, 0, r4, 0, r1.length);
   }
数组的命名
   数组应该总是用下面的方式来命名:
   byte[] buffer;
   而不是:
   byte buffer[];
垃圾收集
JAVA使用成熟的后台垃圾收集技术来代替引用计数。但是这样会导致一个问题:你必须在使用完对象的实例以后进行清场工作。比如一个prel的程序员可能这么写:
   .{
   FileOutputStream fos = new FileOutputStream(projectFile);
   project.save(fos, "IDE Project File");
   }
   ...
   除非输出流一出作用域就关闭,非引用计数的程序语言,比如JAVA,是不能自动完成变量的清场工作的。必须象下面一样写:
   FileOutputStream fos = new FileOutputStream(projectFile);
  project.save(fos, "IDE Project File");
   fos.close();
性能
在写代码的时候,从头至尾都应该考虑性能问题。这不是说时间都应该浪费在优化代码上,而是我们时刻应该提醒自己要注意代码的效率。比如:如果没有时间来实现一个高效的算法,那么我们应该在文档中记录下来,以便在以后有空的时候再来实现她。不是所有的人都同意在写代码的时候应该优化性能这个观点的,他们认为性能优化的问题应该在项目的后期再去考虑,也就是在程序的轮廓已经实现了以后。
   1) 使用 StringBuffer 对象
在处理 String 的时候要尽量使用 StringBuffer 类,StringBuffer 类是构成 String 类的基础。String 类将 StringBuffer 类封装了起来,(以花费更多时间为代价)为开发人员提供了一个安全的接口。当我们在构造字符串的时候,我们应该用 StringBuffer 来实现大部分的工作,当工作完成后将 StringBuffer 对象再转换为需要的 String 对象。比如:如果有一个字符串必须不断地在其后添加许多字符来完成构造,那么我们应该使用 StringBuffer 对象和她的 append() 方法。如果我们用String 对象代替 StringBuffer 对象的话,会花费许多不必要的创建和释放对象的 CPU 时间。
   2) 避免太多的使用 synchronized 关键字
   避免不必要的使用关键字 synchronized,应该在必要的时候再使用她,这是一个避免死锁的好方法。



资料
1:了解MVC
MVC是Model,View,Controller的缩写,MVC是Application开发的设计模式,也就是大家所知道的Model2.在MVC的设计模式中,要求在Application开发中你把商业逻辑,界面显示,数据分离。也就是分别在Model,View,Controller实现:数据,控制(商业逻辑)显示(页面显示).在以前或者说传统的Web Application开发方式当中,如Asp,Php,Jsp(Model 1)开发当中我们在Asp(Php,Jsp)中实现一切,如:从数据库中取到我们需要的数据,并根据数据之间的关联和实际的需要按照某种方式把他显示在页面中以及从页面提交的表单中提取数据,根据商业逻辑从数据库查询相关数据,或者把数据写入数据库。也就是说我们在Asp(Php,Jsp)实现一切包括:界面显示,商业逻辑,数据存取。这样带来的后果就是你所写的Asp(Php,Jsp)
没有层次,并且Html和Script(JavaScript、JScript,Asp、Php、Jsp源代码)相互嵌套.可维护性差,最要命的是在Web Application通常显示一块是由美工完成的,很多时候也是你先写好Asp、Php、Jsp然后美工进行美化,很有可能你发现经过美工处理完以后你的代码已经面目全非了。你不得不把你的代码重新组织。在MVC模式中这个问题的解决办法是:View中负责显示,View一般从Controller得到已经处理过的数据,然后显示在页面当中,应该说这样在Html中嵌套很少的Script.基本上美工的修改不大会废掉你的劳动成果。
2: MVC模式的好处
1) 各施其职,互不干涉
在MVC模式中,三个层各施其职,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。假如业务发生了变化,如在取文章时可能webmaster把一些文章作了无效标志,不能直接把所有文章取出来,只能取出有效的文章,这时业务就发生了改变。再设想一下,如果这个业务逻辑在100个页面中都要用到,那么MVC模式就体现了它的灵活性。我们可以不更改任何JSP,只要更改model层中的相应类中的SQL语句即可。
2) 有利于开发中的分工
在MVC模式中,由于按层把系统开,那么就能更好的实现开发中的分工。网页设计人员可以进行开发视图层中的JSP,对业务熟悉的开发人员可开发业务层,而其它开发人员可开发控制层。
3) 有利于组件的重用
分层后更有利于组件的重用。如控制层可独立成一个能用的组件,视力层也可做成通用的操作界面。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics