代码编码规范

1.目的范围

目的作用:指导、规范软件编程人员进行软件代码编写工作,提高软件开发工程师的软件编写能力。代码规范相当重要,代码规范提高软件代码的可读性,使得开发人员快速和彻底的理解新代码。好的代码风格不仅会提高可读性,而且会使代码更健壮,更为重要的是在修改时不容易出错。编程规范对于程序员而言尤为重要,有以下几个原因: 一个软件的生命周期中,80%的花费在于维护; 几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护; 编程规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码; 如果你将源码作为产品发布,就需要确任它是否被很好的打包并且清晰无误,一如你已构建的其它任何产品; 一些习惯自由程序人员可能对这些规则很不适应,但是在多个开发人员共同写作的情况下,这些规则是必需的。 应用范围:公司所有涉及Java程序编写的人员和部门。本约定适用于可执行系统的源代码文件。为了执行规范,每个软件开发人员必须一致遵守编程规范。 读者对象:分析设计人员、开发人员、软件经理。

2.角色职责

角色名称 职责描述
开发工程师 1.详细设计:确定和定义设计元素的职责、操作、属性和关系;确保设计与软件体系结构一致,并详细到可以继续实施的程度。2.数据库设计:设计将由系统使用的持久数据存储器。3.程序实现:编写程序代码,实现设计策略。
技术评审员 负责及时地提供关于正被评审的项目工件的适当反馈。

3.术语定义

4.规范说明

4.1命名规范

4.1.1文件命名

4.1.1.1通用规则

【规则】 1.一个文件只允许包含一个类,且文件名必需类名相同。如果存在一个文件包含多个类的情况,这时文件名与主要类同名,或者使用概括性描述性的名词、名词短语、动名词短语。 2.文件名称统一用大小写的英文字母、数字和下划线的组合。并且都以大写字母开头,各单词第一个字母需大写,按驼峰表示法命名。 3.命名包括简写命名,要考虑是否比较容易使得自己和别人能明白记住文件包含的内容,所以要考虑文件名的含义。 4.对命名的一个指导原则是当我们在文件夹中使用“按名称排列”的命令时,同一种大类的文件能够排列在一起,以便我们查找、修改、替换、计算负载量等等操作。 5.对于部分不能使用名词、名词短语的.java文件,建议采用动名词的命名结构,即(动词+名词)。

【例子】 StringUtil.java ClientSB.java ClientRemoteHome.java ClientRemote.java

4.1.2标识符命名

4.1.2.1通用约定

【规则】 1.类、异常、对象实例、属性的标识符应选择名词或名词短语,不宜选用动词,并采用驼峰书写模式。 2.尽管一个接口或类拥有多个对象实例,但其名字仍应为单数形式。 3.程序包全部采用小写字母命名,而类、接口、异常等属于类型范畴的标识符以大写字母开头,对象实例、属性、操作(方法)、局部变量等均以小写字母开头,尽量使用完整的英文描述符。 4.采用适用于相关领域的术语。 5.采用大小写混合使名字可读。 6.尽量少用缩写,但如果用了,要清晰、明智地使用,且在整个工程中统一。 7.避免使用长的名字(建议小于18 个字母)。 8.避免使用类似的名字,或者仅仅是大小写不同的名字。 9.避免使用下划线(除静态常量等)。

4.1.2.2程序包命名

【规则】 1.所有程序包名字均采用小写字母命名。一个唯一包名的前缀总是全部小写的ASCII字母并且是一个顶级域名,通常是com,edu,gov,mil,net,org,或1981年ISO 3166标准所指定的标识国家的英文双字符代码。包名的后续部分根据不同机构各自内部的命名规范而不尽相同。这类命名规范可能以特定目录名的组成来区分部门(department),项目(project),机器(machine),或注册名(login names)。

【例子】 com.sun.eng com.apple.quicktime.v2 edu.cmu.cs.bovik.cheese

4.1.2.3类(Class)的一般命名

【规则】 1.类名是个一名词,采用大小写混合的方式,每个单词的首字母大写。尽量使你的类名简洁而富于描述。使用完整单词,避免缩写词(除非该缩写词被更广泛使用,像URL,HTML)。

【建议】 1.使用Controller、Service、*Dao等命名来区分不同职责的Class。

【例子】

class Raster;
class ImageSprite;
class PersonDao;
class LoginController;
class LoginService;
4.1.2.4接口和其实现类的命名

【规则】 1.接口的命名规则与类(class)类似,采用完整的英文描述符说明接口封装,所有单词的第一个字母大写。习惯上,名字后面加上后缀 able, ible 或者 er,但这不是必需的。形容词Runnable、Cloneable是更受欢迎的接口命名约定。 2.接口实现类采用“接口名+Impl”命名。

【建议】 1.利用一个形容词命名接口通常比一个名词更好。

【例子】 接口:Contactable, Prompter 接口实现类:ContactImpl

4.1.2.5异常类的命名

【规则】 1.异常名字通常采用否定形式,建议以Bad、Incomplete、Invalid、Wrong、Missing、Illegal或其他有实际意义的名称来表示异常词作为前缀,后加Exception为后缀来命名,不宜机械使用Error、Exception等含义不清的词。

【例子】 异常可命名:OverflowException、NameWrongException、CharMissingException等。

4.1.2.6属性的命名

【规则】 1.和变量的命名一致。

4.1.2.7获取成员函数的命名

【规则】 1.被访问字段名第一个字母变成对应的大写字母,然后在其加上前缀 get。

【例子】 getFirstName(), getLastName()

4.1.2.8设置成员函数的命名

【规则】 1.被访问字段名第一个字母变成对应的大写字母,然后在其加上前缀 set。

【例子】 setFirstName(), setLastName(),setWarpSpeed()

4.1.2.9布尔型的获取成员函数的命名

【规则】 1.返回值为boolean类型的方法的标识符通常采用is、has或can等前缀,建议只用is做前缀。

【例子】 isPersistent(), isString()

4.1.2.10普通成员函数的命名

【规则】 1.采用完整的英文描述说明成员函数功能,第一个单词尽可能采用一个生动的动词,第一个字母要求小写。

【建议】 1.变量名长度大于等3

【例子】 打开文件openFile()、 新增一个元素addXyz()、 删除一个元素deleteXyz()、 更新一个元素 updateXyz()、 查找元素 findXyz()、 Xyz为元素名词。

4.1.2.11变量的命名

【规则】 1.变量采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。变量名不应以下划线或美元符号开头,尽管这在语法上是允许的。 2.变量名应简短且富于描述。变量名的选用应该易于记忆,即能够指出其用途。 3.尽量避免单个字符的变量名,除非是一次性的临时变量。在简单循环中的循环计数器可命名为i、j、k、index或counter;复杂的循环或循环计数器在问题域有明确对应术语时不得如此命名。

【建议】 1.变量名长度大于等3,小于等于20

【例子】 char c; int i; float myWidth; int counter;

4.1.2.12常量的命名

【规则】 1.类常量的声明,应该全部大写,单词间可以用下划线隔开。

【例子】 static final int MIN_WIDTH = 4; static final int MAX_WIDTH = 999; static final int GET_THE_CPU = 1;

4.1.2.13参数的命名

【规则】 1.参数的名字必须和变量的命名规范一致。 2.使用有意义的参数命名,如果可能的话,使用和要赋值的字段一样的名字。 【例子】 setCounter(int size){ this.size = size; }

4.1.2.14数组的命名 【规则】 1.数组的命名和变量的命名规则相同。 【例子】 byte[] buffer; 而不是: byte buffer[];

4.1.2.15EJB组件的命名

【规则】 1.EJB规范中定义的会话组件、实体组件、消息组件分别由Home接口、Remote接口和组件类构成,因此,在组件接口对象和组件类的创建过程中,应遵循统一的命名规则。 2.实体Bean的命名约定:组件类为EB,Home接口类为RemoteHome或者LocalHome,Remote接口类为Remote或者Local。 3.会话Bean的命名约定:组件类为SB,Home接口类为RemoteHome或者LocalHome,Remote接口类为Remote或者Local。 4.消息Bean的命名约定:组件类为*MB。 【例子】 ClientEB,ClientRemoteHome,ClientRemote,ClientLocalHome,ClientLocal PurchaseSB,PurchaseRemoteHome,PurchaseRemote,PurchaseLocalHome,PurchaseLocal

4.2结构规范

4.2.1声明结构

4.2.1.1声明变量

【规则】 一行只声明一个属性或局部变量,并在同一行注释该属性或局部变量的作用、取值范围、原因等。 方法实现体中先声明局部变量再书写语句部分,变量声明与语句部分之间以一个空行分隔;在语句部分,可将空行用于分隔不同的逻辑相关语句组;除循环计数器外,禁止在语句中间声明局部变量。 【例子】

// 规范良好的风格
int level;  // indentation level
int size;   // size of table
//容易出错的风格
int level, size; 

//更不能将不同类型变量的声明放在同一行,例如:
int foo,  fooarray[];   //WRONG!

注意:上面的例子中,在类型和标识符之间放了一个空格,另一种被允许的替代方式是使用制表符:

int        level;         // indentation level
int        size;          // size of table
Object    currentEntry;  // currently selected table entry

4.2.1.2初始化 【规则】 尽量在声明局部变量的同时初始化。唯一不这么做的理由是变量的初始值依赖于某些先前发生的计算。

4.2.1.3布局 【规则】 1.只在代码块的开始处声明变量。(一个块是指任何被包含在大括号"{"和"}"中间的代码。)不要在首次用到该变量时才声明之。这会把注意力不集中的程序员搞糊涂,同时会妨碍代码在该作用域内的可移植性。 2.避免声明的局部变量覆盖上一级声明的变量。 【例子】

  void myMethod() {
      int int1 = 0;         // beginning of method block
      if (condition) {
          int int2 = 0;     // beginning of "if" block
          ...
      }
  }

【例外】 //该规则的一个例外是for循环的索引变量

  for (int i = 0; i < maxLoops; i++) { ... }
//不好的实践:要在内部代码块中声明相同的变量名
  int count;
  ...
  myMethod() {
      if (condition) {
          int count = 0;     // AVOID!
          ...
      }
      ...
  }
4.2.1.4类和接口的声明

【规则】 当编写类和接口时,应该遵守以下格式规则:

  • 在方法名与其参数列表之前的左括号"("间不要有空格
  • 左大括号"{"位于声明语句同行的末尾
  • 右大括号"}"另起一行,与相应的声明语句对齐,除非是一个空语句,"}"应紧跟在"{"之后

    class Sample extends Object {
        int ivar1;
        int ivar2;
    
        Sample(int i, int j) {
            ivar1 = i;
            ivar2 = j;
        }
    
        int emptyMethod() {}
    
        ...
    }
    
  • 方法与方法之间以空行分隔

4.2.2语句结构

4.2.2.1简单语句

【规则】 每行至多包含一条语句,例如:

//好的方式
argv++;       // Correct
argc--;       // Correct

//不好的方式
argv++; argc--;  // AVOID!
4.2.2.2复合语句

【规则】 复合语句是包含在大括号中的语句序列,形如"{ 语句 }"。例如下面各段。 被括其中的语句应该较之复合语句缩进一个层次。 左大括号"{"应位于复合语句起始行的行尾;右大括号"}"应另起一行并与复合语句首行对齐。 大括号可以被用于所有语句,包括单个语句,只要这些语句是诸如if-else或for控制结构的一部分。这样便于添加语句而无需担心由于忘了加括号而引入bug。

4.2.2.3返回语句

【规则】 一个带返回值的return语句不使用小括号"()",除非它们以某种方式使返回值更为显见。例如: return; return myDisk.size(); return (size ? size : defaultSize);

4.2.2.4条件语句(if,if-else,if else-if else)

【规则】 if-else语句应该具有如下格式:

  if (condition) {
      statements;
  }

  if (condition) {
      statements;
  } else {
      statements;
  }

  if (condition) {
      statements;
  } else if (condition) {
      statements;
  } else{
      statements;
  }

注意:if语句总是用"{"和"}"括起来,避免使用如下容易引起错误的格式: if (condition) //AVOID! THIS OMITS THE BRACES {}! statement;

4.2.2.5循环语句(for)

【规则】 一个for语句应该具有如下格式: for (initialization; condition; update) { statements; }

一个空的for语句(所有工作都在初始化,条件判断,更新子句中完成)应该具有如下格式: for (initialization; condition; update);

当在for语句的初始化或更新子句中使用逗号时,避免因使用三个以上变量,而导致复杂度提高。若需要,可以在for循环之前(为初始化子句)或for循环末尾(为更新子句)使用单独的语句。

4.2.2.6循环语句(while)

【规则】 一个while语句应该具有如下格式 while (condition) { statements; }

一个空的while语句应该具有如下格式: while (condition);

4.2.2.7循环语句(do-while)

【规则】 一个do-while语句应该具有如下格式: do { statements; } while (condition);

4.2.2.8分情语句(switch)

【规则】 一个switch语句应该具有如下格式:

  switch (condition) {
  case ABC:
      statements;
      /* falls through */
  case DEF:
      statements;
      break;
  case XYZ:
      statements;
      break;
  default:
      statements;
      break;
  }

每当一个case顺着往下执行时(因为没有break语句),通常应在break语句的位置添加注释。上面的示例代码中就包含注释/ falls through /。 每个switch语句应包括一个default选项。default选项里的break是冗余的,但可预防以后增加另一个选项后没有中断执行导致错误的情况出现。

4.2.2.9异常捕获语句(try-catch)

【规则】 一个try-catch语句应该具有如下格式:

  try {
      statements;
  } catch (ExceptionClass e) {
      statements;
  }

一个try-catch语句后面也可能跟着一个finally语句,不论try代码块是否顺利执行完,它都会被执行。

  try {
      statements;
  } catch (ExceptionClass e) {
      statements;
  } finally {
      statements;
  }
4.2.3类结构

【规则】 所有类的第一行是包定义,然后空一行,接着是一条或多条包引入(import)声明,包引入完成后空一行按类注释规范写入类注释,接着类注释换行后就是类定义。每个类定义在类名后或继承类和实现多个接口后,间隔一个空格以“{”开始再换行,紧接书写属性定义和方法定义,最后换单独一行对齐类的可见限定符(public)首字母输入“}”结束该类定义。 所有属性定义要优先于方法先定义。 方法体的代码行数不宜超过一屏幕的内容,一屏代码行数大概50行左右。

【例子】

package com.citic.xxx.model;

import java.io.*;
import java.util.*;

/**************************************************************************
 * @Title:  <p>类主题名称</p>
 * @Description:<p>说明本业务接口的应用,以及与实现相关的其他说明。
 *         说明本业务接口的应用,以及与实现相关的其他说明。说明本业
 *         务接口的应用,以及与实现相关的其他说明。</p>
 * @Copyright:<p>中信网络科技股份有限公司 Copyright (c) 2016 </p>
 * @Author:  <p>创建的作者</p>
 * @Records: <p>[版本号1]  该版本实现创建作者  创建说明</p>
 *           <p>[版本号2]  该版本实现所作改进的作者  改进内容说明</p>
 *           <p>[版本号3]  该版本实现所作改进的作者  改进内容说明</p>
 *************************************************************************/
public class Person {
    private String name;  // 姓名
    private String sex;   // 性别(“0”-女,“1”-男)

    /**
     * @function: <p>说明该方法的含义、作用和如何用(What、Why、How)</p>
     * @param: <p>各个参数说明</p>
     * @return:<p>返回值说明</p>
     * @throws:<p>说明抛出的异常</p>
     * @records: <p>[20160808] 张三 创建</p>
     */
    public String getName() {
        return this.name;
    }

    /**
     * function: <p>说明该方法的含义、作用和如何用(What、Why、How)</p>
     * @param: <p>各个参数说明</p>
     * @return:<p>返回值说明</p>
     * @throws:<p>说明抛出的异常</p>
     * @records: <p>[20160808] 张三 创建</p>
     */
    public void setName(name) {
        this.name = name;
    }

    /**
     * @function: <p>说明该方法的含义、作用和如何用(What、Why、How)</p>
     * @param: <p>各个参数说明</p>
     * @return:<p>返回值说明</p>
     * @throws:<p>说明抛出的异常</p>
     * @records: <p>[20160808] 张三 创建</p>
     */
    public String getSex () {
        return this.sex;
    }

    /**
     * @function: <p>说明该方法的含义、作用和如何用(What、Why、How)</p>
     * @param: <p>各个参数说明</p>
     * @return:<p>返回值说明</p>
     * @throws:<p>说明抛出的异常</p>
     * @records: <p>[20160808] 张三 创建</p>
     */
    public void setSex(sex) {
        this.sex = sex;
    }
}

4.3注释规范

良好的程序注释可帮助提高程序源代码的清晰度。注释的目的是要使代码更易于被同时参与程序设计的开发人员以及其他后继开发人员理解。 程序注释方式很大程序上影响着程序员的工作效率以及所有负责维护、改进程序代码的后继开发者的工作效率。在软件开发过程中及早注释代码,会促使程序员在编写代码前仔细考虑这些代码,从而提高工作效率。程序维护人员重新阅读以前的代码时,可很容易地判断出当时程序员的想法,因为这些思路均有记录可查。 各种注释、文档与手册之间尽量避免重复。本指南已考虑到这种重复性,例如在组件方法基调中已注释过形式参数,则在组件方法实现中不重复注释形式参数。

4.3.1注释原则

【规则】 1.注释总则:编写程序时,先注释后编码;修改代码时,也是先修改注释、再修改代码。 2.注释不仅列出相应代码的功能,而且还应给出如此编写代码的原因及思路。 3.注释以清晰、实用为目的,避免使用广告横幅那样的装饰性注释风格。 4.如果本指南约定的注释条目内容为空,则该注释条目的整行都不必出现。 5.如果本指南约定的注释条目有必要出现,则出现次序须照本指南约定。 6.注释条目关键字为复数形式表示该条目可列多项,各项之间以逗号分隔。 7.修改别人的代码时,必须添加修改人名称、修改日期及修改原因

【约定】 1.对于用户界面为中文的软件产品,程序中的注释均采用中文书写。 2.代码里面可以采用“//”和“//”两种注释方法。但要注意:(1)针对文件整体描述的注释采用“//”;(2)针对类的注释采用“//”;(3)针对方法的注释采用“//”;(4)针对全局变量属性的注释采用“//”;(5)在方法内部的说明均采用以“//”前缀的行尾注释风格;(6)注释符号“/ ... /”在程序内部只限用于临时隐藏无用代码,此时应注明隐藏代码的时间、作者和原因。 3.要求在针对类和方法的注释中,尽量采用Sun提出的javadoc注释方法。 4.日期书写格式:采用中国格式“yyyy-mm-dd”。 5.版本号书写格式:版本号包括由两个小数点分开的三部分,格式例如X1.X2.X3。X1表示版本编号,这是产品的升级版。X2代表产品的局部升级版。X3代表日常修改的日期,如20030813。例如1.0.20030813代表第一代版本开发版的2003.08.13的修改日期。 6.对于EJB组件,要求在Remote接口类中必须有针对每一个方法的注释;不要求对Home接口类有必要的注释;在每一个实现类中必须有针对EJB组件的详细说明,但不要求对已经在Remote接口类中出现过的方法的注释。 7.对于jsp等其他非.java文件也可参照.java文件的注释格式。

【建议】
1.对于一行写不完的注释条目可换行续写,第二行开始在“//”与正文之间插入两个Tab键。

【备注】 1.Sun Microsystems公司建议了一种文档注释标准,使得自动化文档工具javadoc可从Java源程序中抽取出文档信息。 2.这种注释风格为/* ... /,在注释中以@auther name、@since等关键字标记注释条目。

4.3.2程序文件的注释

【规则】 1.对于EJB组件,要求在Remote接口类中必须有针对每一个方法的注释;不要求对Home接口类有必要的注释;在每一个实现类中必须有针对EJB组件的详细说明,但不要求对已经在Remote接口类中出现过的方法的注释。 2.在业务接口源程序的开头注释如下条目:

/*********************************************************************************
 * @Title:<p>名称</p>
 * @Description: <p>说明本业务接口的应用,以及与实现相关的其他说明。</p>
 * @Copyright: <p>企业名称 Copyright (c) 2003</p>
 * @Author:<p>作者</p>
 * @Records:<p>[版本号1] 第一版创建者  创建</p>
 *               <p>[版本号2]  该版本实现所作改进的作者  改进内容说明</p>
 *               <p>[版本号3]  该版本实现所作改进的作者  改进内容说明</p>
 *********************************************************************************/

在业务接口方法源程序的开头注释如下条目:

/**
* @function:<p>清晰、简洁地说明本方法的功能(What、Why、How)</p>
* @param:<p>逐行列出每一参数的含义</p>
* @return:<p>描述返回结果的含义</p>
* @throws:<p>逐行列出每一异常抛出的原因,不必列出EJB强制的RemoteException或其他异常</p>
* @records: <p>[8年月日]  作者   增加(修改)的内容</p>
*              <p>[8年月日]  作者   增加(修改)的内容</p>
*/

其中“[版本号]”的构成如下: <大版本号>.<小版本号>.<完成日期(八位年月日)> 如:[1.0.20161018], [1.0.20161109], [1.1.20161230]

【例子】 程序员希望保留某段代码的旧版本备用,可注释如下:

/*********************************************************************************
 * @Title:<p> DatabaseAccess</p>
 * @Description: <p> 实现JDBC与数据库的连接,为应用程序提供简便的数据库操作方法。
 *                     通常本类的一个对象实例仅用于访问一次数据库(即只执行一条SQL语句)。</p>
 * @Copyright: <p>中信网络科技股份有限公司Copyright (c) 2016</p>
 * @Author: <p>张三</p>
 * @Records:<p>[1.0.20150808]  张三    创建</p>      
 *               <p>[1.0.20150818]  张西   修改initialURLConnection()方法</p>
 **********************************************************************************/
class Client {
      int a;//属性注释

      /**
        * @function:<p>修改某一用户的相关资料。</p>
        * @param:<p>id(原用户标识), user(新用户记录)</p>
        * @return:<p>void</p>
        * @throws:<p> UserNotFound(用户标识id不合法),NameWrong(用户名称错误) </p>
        * @records: <p>[20150808]  张三     创建</p>
         *                <p>[20150918]  李四     修改xxxxxxx</p>
         */
        void getA(){
              ….
              //注释A
              A=doA();
              /* 本段代码已由上列代码替代,2001.09.10由张三注释。建议一年内未用上这些代码则将其删除。
              ...  (被隐藏的源代码)
              */
         }
}

4.4版面规范

统一、美观的缩进与分隔对编译器没有作用,但可显著提高程序的可读性。 可采用Eclipse默认风格或引入公司统一风格文件。采用Eclipse的format功能进行版面整理。 java代码全部使用utf-8编码,避免出现注释或者内容乱码。 删除代码中多余空白行(必要的空白行除外,4.4.3说明),注释行(必要的空白行除外),未使用的import等无效代码(可使用CTRL+SHIFT+F格式化代码)。 在正式发布的代码中,打印输出时务必采用日志方式,不允许使用System.out。

4.4.1缩进与分隔符

【规则】 1.全部采用制表符缩进,不采用固定数目的空格表示缩进。 2.两个单词(保留字、标识符)之间以一个空格作分隔。 3.所有单目操作符(不论在前还是在后)与其操作数之间不分隔。 4.所有双目操作符与其左、右操作数之间都以一个空格作分隔。 5.各种括号(包括圆括号、方括号、尖括号等)与其括号中的内容不分隔。 6.括号外的标点符号与左边标识符不分隔,与右边标识符以一个空格作分隔。

【例子】 以下if语句与表达式的写法遵循了上述缩进与分隔规则:

if (!hasNext()) {
average = total / ( male + female );
table.addCell("Average", average);
}

4.4.2代码长度

【规则】 1.方法体代码行数长度不得超过50行; 2.方法中嵌套层次不能超过5层; 3.方法参数个数不得超过10个; 4.类总代码长度不得超过1000行。

4.4.3空白

4.4.3.1空行

空行将逻辑相关的代码段分隔开,以提高可读性。 【规则】 下列情况应该总是使用两个空行: 一个源文件的两个片段(section)之间 类声明和接口声明之间 下列情况应该总是使用一个空行: 两个方法之间 方法内的局部变量和方法的第一条语句之间 块注释(参见"4.3.1")或单行注释(参见"4.3.2")之前 一个方法内的两个逻辑段之间,用以提高可读性

4.4.3.2空格

【规则】 下列情况应该使用空格: 一个紧跟着括号的关键字应该被空格分开,例如: while (true) { ... }

注意:空格不应该置于方法名与其左括号之间。这将有助于区分关键字和方法调用。 空白应该位于参数列表中逗号的后面 所有的二元运算符,除了".",应该使用空格将之与操作数分开。一元操作符和操作数之间不因该加空格,比如:负号("-")、自增("++")和自减("--")。例如: a += c + d; a = (a + b) / (c * d);

while (d++ = s++) {
    n++;
}
printSize("size is " + foo + "\n");

for语句中的表达式应该被空格分开,例如: for (expr1; expr2; expr3)

强制转型后应该跟一个空格,例如: myMethod((byte) aNum, (Object) x); myMethod((int) (cp + 5), ((int) (i + 3)) + 1);

4.5程序包规范

在Java语言中,程序包(package)用于组织相关的接口或类。如何确定哪些接口与类是相关的,并将它们组织为程序包,是程序设计人员控制的事情。 程序包的组织等价于设计存放各种.java文件的目录层次结构。

【规则】 通常采用平坦方式组织子目录,即在应用程序的主目录下直接将所有的程序包作为子目录,程序包中的各个.java文件存放在相应的子目录中。 从逻辑上看,程序包分为两种类别:一是专用于某一软件产品的,一是可在不同应用领域重用的基础程序包。从物理上看,采用平坦方式组织子目录时这两者没有区别。 随着公司内部对JavaEE平台由产品的不断研发,将会在计算机软件领域(如更高层次的GUI组件、更专业的数据表组件等)以及各专业应用领域(如物流组件、财务组件、人力资源组件等)形成高度可重用的组件,这时可考虑将平坦方式改为层次方式,即把某些相关的程序包再组织为更大的程序包。

【例子】

com.icitic
      |_ .crp
      |   |_ .controller
      |   |_ .service
      |   |   |_ .impl
          |   |_ .dao
      |   |   |_ .impl
      |   |_ .entity
      |   |_ .vmo
      |   |_ .view
      |   |_ .util
      |_ .common
      |_ .sys

采用层次方式时,com表示公司顶级包,其子目录包含的是以公司名称命名的包;com.icitic是公司名称包,在其子目录下包含公司所有的应用系统顶级包和通用包;com.icitic.crp是当前应用系统包,在com.icitic.sys子目录中包含在编程领域中可重用的高层组件;在com.icitic.crp.service下是crp应用的分层结构中服务包,其它包都属于crp应用按分层架构设计的包路径。

4.6JSP编码规范

【规则】 1.JSP或者html名称,全部使用小写字符,允许只用中划线,不允许使用驼峰命名方式。 2.不应在Jsp中使用java语句处理任何逻辑,而是通过把业务数据(模型)通过控制器转换成Json后交给页面的JavaScirpt及其相关库与框架(如jQuery或AngularJS等)处理。 3.整个jsp/jsp bean表示层应当尽可能的瘦和简单化。 4.牢记大多数的JSP都应当是只读的视图,而由bean来提供模型。 5.在尽可能合理的情况下,把业务逻辑从JSP中移走。具体于HTTP的逻辑(如,对Cookie的处理)属于bean或支持类中,而不是JSP中。 6.应把条件逻辑放在控制器中而不是放在视图中。 7.jsp不应该直接去访问请求参数。bean应当执行这样的处理过程并且输出所处理的模型数据。 8.jsp不应当访问属性文件,或者使用JNDI。bean可以访问属性。 9.应当避免设计既显示表单又处理结果的页面。 10.jsp层不应该直接访问数据,这包括JDBC数据库访问和EJB访问。 11.如果使用了,并且必须使用简单类型的值来与外部页面进行通讯的话,就应当使用一个或多个元素 12.定制标记应当用在适当把逻辑从jsp中移走的地方。 13.应当谨慎地使用标记,在jsp中它是一个等价的goto。 14.应当使用隐藏的注释来阻止输出的HTML过大。 15.在jsp中避免进行异常处理 16.每个jsp文件中都应当使用一个错误页面来处理不能够从中恢复的异常。 17.在jsp错误页面中,使用HTML注释来显示传递到该页面中的异常跟踪信息。

5.编程模式

良好的编程模式可以提高代码可读性、可维护性和可复用性及,以及获得合理的性能指标。编程模式是这种良好编程实践在特定场景的经验总结,并可复用于相识的编程场景。以下17个编程模式,来自大多数项目成功的经验总结,遵循其能对提升编程质量带来很大益处。

1.不能重复引入;不能无效引入。 避免下面的引入方式:

// 重复引入
import java.util.Date;
import java.util.*;

// 无效引入
import java.lang.String;

// 不要引入*
import java.util.*;

2.用接口代替实现类;用父类代替子类。 【建议】 使用List 替换 Vector 使用 Map 替换 Hashtable 使用Iterator 替换 Enumeration

3.避免使用new关键字来创建String对象。把一个String常量copy到String 对象中通常是多余、浪费时间的。 【例子】

Public class test{
 Public void method(){
  System.out.print (str);
 }
 private String str = new String ("1"); //这里新建对象是完全没有必要的
 private String str2=”2//正确的应该如此
}

4.避免使用不必要的嵌套。过多的嵌套会使你的代码复杂化,减弱可读性。 【例子】

public class test {
 String add (){
  int c = (a=a+b)+b; //过于复杂
  Return c
 }
}

5.在每一行里只写一条语句。这条规则不包括for语句,比如:'for (int i = 0; i < 10; i++) x--;’可以增加代码的可读性。 【例子】

// 不好的实践
public class OSPL {
 int method (int a, int b) {
  int i = a + b; return i; // 可读性不强
 } 
}
// 良好的实践
public class OSPLFixed {
 int method (int a, int b) {
  int i = a + b; 
  return i; 
 }
}

6.经常从finalize ()中调用super.finalize ()。这里的finalize ()是java在进行垃圾收集的时候调用的,和finally不一样。如果你的父类没有定义finally()的话,你也应该调用。这里有两个原因:(1)在不改变代码的情况下能够将父类的finally方法加到你的类中。 (2)以后你会养成习惯调用父类的finally方法,即使父类没有定义finally方法的时候。 【例子】

// 正确的方法应该如此:
public class parentFinalize {
 protected void finalize () throws Throwable {
  super.finalize(); // FIXED 
 } 
}

7.不要在finalize ()中注销listeners。不要再finalize ()方法中中注销listeners,finalize ()只有再没有对象引用的时候调用,如果listeners从finalize()方法中去除了,被finalize的对象将不会在垃圾收集中去除。 【例子】

public void finalize () throws Throwable {
 bButton.removeActionListener (act); 
}

8.不要显式的调用finalize ()方法。虽然显式的调用这个方法可以使你确保你的调用,但是当这个方法收集了以后垃圾收集会再收集一次。 【例子】

public class T7 {
 public void finalize() throws Throwable { 
  close_resources (); 
  super.finalize ();
 }
 public void close_resources() {}
}
class Test {
 void cleanup () throws Throwable {
  t71.finalize(); // 调用 
  t71 = null; 
 }
 private t71 = new T7 ();
}

对于这样的调用我们应该自己创建一个释放的方法,做最初finalize ()所作的事情,当你每次想显式的调用finalize ()的时候实际上调用了释放方法。然后再使用一个判断字段来确保这个方法只执行一次,以后再调用就没关系了。

public class T7 {
 private boolean _released = false;
 public synchronized void release () throws Throwable{
  if (!_released) { 
   close_resources (); // do what the old 'finalize ()' 
   did _released = true; 
  }
 }
 public void finalize () throws Throwable {
  release (); 
  super.finalize ();
 }
 public void close_resources() {
} 
}
class TestFixed {
 void closeTest () throws Throwable {
  t71.release (); // FIXED 
  t71 = null;
 }
 private T7 t71 = new T7 ();
}

9.不要使用不推荐的API。尽量使用JDK1.3以上推荐的API。在类和方法或者java组件里有很多方法是陈旧的或者是可以选择的。有一些方法SUN用了"deprecated“标记。 最好不要使用例如: private List t_list = new List (); t_list.addItem (str);
如果查一下javadoc的话,会发现建议用add()来代替addItem()。

10.为所有序列化的类创建一个'serialVersionUID'。可以避免从你各种不同的类破坏序列的兼容性。如果你不特别制订一个UID的话,那么系统为自动产生一个UID(根据类的内容)。如果UID在你新版本的类中改变了,即使那个被序列化的类没改变,你也不能反序列化老的版本了。 【例子】

public class DUID implements java.io.Serializable { 
public void method () {
}
}

在里面加一个UID,当这个类的序列化形式改变的时候,你也改变这个UID就可以了。 【例子】

public class DUIDFixed implements java.io.Serializable { 
 public void method () {
} 
 private static final long serialVersionUID = 1;
}

11.对于private常量的定义,比较好的做法是对于这样的常量,加上final标记,这样的常量从初始化到最后结束值都不会改变。 【例子】

private int size = 5;  
// 改变后的做法
private final int size = 5;

12.避免把方法本地变量和参数定义成和类变量相同的名字。这样容易引起混扰,建议把任何的变量字都定义成唯一的。 【例子】

// 不建议(这里标识符j不是唯一的)
public void method (int j)  { 
final int i = 5; // VIOLATION
} 
private int j = 2; 

// 建议
public void method (int j1) { 
final int i = 5; // VIOLATION 
} 
private int j = 2;

13.让构造器尽量少做事。 构造器是用来创建一个类的实例。构造器的名字永远是跟这个类的名字是一样的。既然构造器的名字无法改变,那么它就不能表达出它做的事情的含义。所以,最好是尽可能的让构造器少做点事,理想的情况就是构造器仅用来接受参数给实例变量加载数据。下面的例子表明,很大程度上是因为构造器十分的简单,更多的让状态变更和行为方法来完成其他的部分,使得一个软件具有很高的可读性。 【例子】

public class CustomerAccount implements ICustomerAccount{
// 实例变量
private String username;
private String password;
protected String accountStatus;
// 构造器执行了最小的工作量
public CustomerAccount(String username, String password) {
  this.password = password;
  this.username = username;
}
}

14.方法名要清晰的表现意图。 表意清晰的长名字会帮助开发团队快速的理解他们软件的功能意图。例如isRequestedUsernameValid()让开发人员知道这个方法时用来验证用户名是否正确的。相反的,isGoodUser() 可能有很多用途:用来验证账号是否是激活的,用来验证用户名或者密码是否正确,或者是用来搞清楚用户是不是个好人。方法名表意不清,这就很难让开发者明白这个方法到底是用来干什么的。简单的说,长一点并且表意清晰的方法名要比又短又表意不明的方法名好。

15.一个对象只进行一类服务。 一个对象只处理一小部分事情将使得代码更好读好用,因为每个对象代码量很少。更糟糕的是,重复的逻辑将花费很多时间和成本去维护。

16.状态变更方法少含有行为逻辑。 混合了状态变更逻辑和行为逻辑的代码让人很难理解,因为在一个地方处理了太多的事情。状态变更方法涉及到远程调用来存储数据的话很容易产生系统问题。如果远程方法是相对独立的,并且方法本身没有行为逻辑,这样诊断起状态改变方法就会十分容易。另外一个问题是,混合了行为逻辑的状态代码很难进行单元测试。

17.可以任意次序调用行为方法。 要保证每个行为方法之间保持着独立。换句话说,一个对象的行为方法可以被重复或任何次序来调用。这个习惯能让对象实现稳定的行为。比如,CustomerAccount's isActiveForPurchasing()和getPostLogonMessage() 行为方法都要用到accountStatus的值。这两个方法必须在功能上相互独立。

6.裁剪指南

本规范不能裁剪,必须完全按照上述具体内容遵照执行。“5编程模式”是良好的编程实践,应根据实际场景遵循该模式建议和指导。

results matching ""

    No results matching ""