后台编码规范

  •  一、 方针

此编码标准是在软件开发,提供用java 编码时的规则,推荐,以及困惑时的查询。标准制定的方针是写容易读,容易维护的代码。在实际的编码中,需要项目组成员全体遵守此规则。

  •  二、文件构成

  •  (一)文件名

public 类要当作其类名的1个文件.

例: public class Point 要放到Point.java 中

软件包内的非Public类包含在其类被主要使用的Public类的文件中为好(此时,要注意*.java 和*.class 不对应).

  •  (二)文件的位置

决定Project的根目录,将软件包名的“.”放入置换到目录阶层的位置中.

例: myProject.framework 软件包配置在/myProject/framework 目录中

例: com.netmarch.dto软件包配置在>ProjectRoot</com/netmarch/dto 目录中

  •  (三)测试类名

类ClassName 的综合测试类名为ClassNameTest .每个软件包测试为LastPackageNameTest .

例: Point2D 类的话,作成Point2DTest.java .

例: com.netmarch.extremedomo软件包的话,作成ExtremeDomoTest.java .

理由: 起一个有一贯性的名字.测试代码为使用方法的样品.

其他方法: 将ClassName 的综合测试类名作为ClassNameUt (Ut 为UnitTest之略)

  •  三、命名规则

  •  (一)软件包名

用“.” 隔开的文字.

例:com.netmarch.domainname.projectname

例:junit.framework

建议在实际的项目中,包的命名由项目经理和开发组长来制定,在整个项目中使用统一的包名及类名。结合本公司的实际,制定一个参考如下(都位于/src目录下):

com.netmarch.domain//存放DTO,POJO,JAVABEAN

com.nemtarch.spring//存放Spring的相关文件

com.netmarch.struts.actin//存放struts的ACTION类

com.netmarch.struts.form//存放struts的FORM类

com.netmarch.filter//存放过滤器,如session过滤器,字符过滤器等

com.netmarch.listener //存放监听器,如访问流量监听器,商业软件中的配置文件读取监听器

com.netmarch.util //存放公用的类库,以后完善了我们公司的类库过后,就可以只用导入一个JAR包就可以啦

com.netmarch.maps //存放iBATIS的XML配置文件

com.netmarch.interface //存放接口类

com.netmarch.infaimpl //存放接口实现类(这个可以根据需要,也可以用com.netmarch.dao)

com.netmarch.dao //实体操作类

com.netmarch.abst //存放抽象类

com.netmarch.hibernate//存放hibernate相关类

com.netmarch.service //业务接口外部调用类

com.netmarch.common //基本配置类

com.netmarch.excel //生成EXCEL的操作类

(根据项目的不同,下面可以再添加相关的包,这个可以由PM来决定)

  •  (二)文件名

Public类名要根据编译程序的规则,必须是和文件名相同(包含大写小写的区別).

  •  (三)类名

开头大写.后面将隔开作为大写.

例:CapitalizedWithInternalWordsAlsoCapitalized

  •  (四)接口名

同类名.但是,如果有和class 区別的必要的话,最开始加I .

例:InameOfInterface

  •  (五)实现类名

特别是有和interface 区別的必要的话,最后加Impl .

例:ClassNameEndsWithImpl


  •  (六)抽象类名

没有适合抽象类名的名字时,从Abstract 开始,起一个联想SubClass名的名字.

例:AbstractBeforeSubClassName


  •  (七)方法名

最开始是小写,后面隔开用大写.

firstWordLowerCaseButInternalWordsCapitalized()

  •  (八)Factory方法

例:X newX()

X createX()

  •  (九)Converter方法

X toX()

  •  (十)属性的设定方法

在void setX(X value) // JavaBeans 可以作为Proverty(标准)来用(推荐)

  •  (十一)返回Boolean变量的方法

is + 形容词,can + 动詞,has + 过去分词,三单元动词,三单元动词+ 名词.

例:boolean isEmpty()

boolean empty() // 不行!因为能取’空’的动词的意思,所以不好.

boolean canGet()

boolean hasChanged()

boolean contains(Object)

boolean containsKey(Key)

理由: if, while 文等的条件会变为容易读.还有true 是哪个意思容易懂.


  •  (十二)名字的对称性

取类名,方法名时,注意以下英語的对称性.

add/remove   insert/delete   get/set

start/stop   begin/end   send/receive

first/last   get/release   put/get

up/down   show/hide   source/target;

open/close   source/destination   increment/decrement;

lock/unlock   old/new   next/previous

  •  (十三)大写小写

大写和小写被作为其他的文字来用,但不能取仅用此区別的名字.


  •  (十四)Loop Counter

范围(通用范围)较小的Loop Counter,重复中将i, j, k 的名字按顺序使用.


  •  四、指南

编码形式是以Sun Microsystems, Inc 的JDK 源程序为准.编排基本上是和K&R 的C 语言形式相同,但将类及方法的定义开头的”{“不改行写.

/* COPYRIGHT ...
* ...        文件开头有时有copywrite.这里不是/** ,而是/* 的注释.
*/
package myProject.util;       然后,package,1行空,import 的罗列
import java.util.Stack;
在import java.util.Vector;类定义之前从关于类的/**开始的注释.第1行短,明白说明类.用半角句号结束.从下一行开始详细说明.继续行按照第2个*,将* 放在开头.
/**************************************************
 * FileName:DaoConfig.java
 * Version: 1.00
 * Author: Bruce
 * Date: 2006-07-27
 * Last modify Date: 2006-07-26
 * Function: 读取配置文件以获取相关的信息
 * CopyRight (c) Netmarch Company 2006
 *	All rights reserved
 **************************************************/

                        

类定义开始的”{“ 不改行.public class Stack 定义开始的”{“ 不改行.

/**                          方法的注释也和类同样.
*追加要素.                 @param, @return, @exception(如有)为
* @param item 追加的要素   必须.根据需要@see 等.
*/
public void push(Object item) {                 方法定义开始的”{“ 也不改行.
if (itemCapacity <= itemCount) {
// ...                             if, while 等的关键词和“(“之间空一格.
字朝下          } else                                 (方法名后面的”(“无空格).”(“的后面不空,
1TAB=4 SPACE. {                                      运算符的两侧空格.”(“的后面空格, 继续
// ...                                “{“.
}       注意用if/else 的“{“, “}”的位置.
}
/**
*取得开头要素.开头要素被除去.
* @return 开头要素
*/
public Object pop() {
// ...
return top;      不用()包围return 值.
}
}
                        

其他方法: 关于缩排,{} 的位置,为了不破坏各自的创造性,不敢规定.

  •  (一)编码形式

  •  (二)较长的行

一行最大80 个字,超过时要分行.分割的指針是,(1) 利用Local变量,(2)用回车键改行,(3)在优先低的运算符的前面改行.

例:

double length = Math.sqrt(Math.pow(Math.random(), 2.0) +
Math.pow(Math.random(), 2.0));
// 方针(1)
double xSquared = Math.pow(Math.random(), 2.0);
double ySquared = Math.pow(Math.random(), 2.0);
double length = Math.sqrt(xSquared + ySquared);
// 方针(2)
double length = Math.sqrt(Math.pow(Math.random(), 2.0,
Math.pow(Math.random(), 2.0);
// 方针(3)
return this == obj
|| (this.obj instanceof MyClass
&& this.field == obj.field);

                        


  •  (三)较长的声明行

类,方法的声明很长时,(1) 用extends/implements/throws 节改行,(2) 用回车键改行.

例:

public class LongNameClassImplemenation
extends AbstractImplementation,
implements Serializable, Cloneable {
private void longNameInternalIOMethod(int a, int b)
throws IOException {
// …
}
public void longMethodSignature(int a, int b, int c,
int d, int e, int f) {
// …
}
// …
}

                        


  •  (四)import

在import 尽量不使用* .从同一个软件包import3个以上的类时,使用* .

理由: 将依存性明确化.如有使用了多个*的import ,读起来辛苦.但是,重复使用某个软件包时等(会用).


  •  (五)Abstract class 和interface

抽象类(abstract class)尽量不使用,而多用interface 吧.abstract class 仅在有一部分安装,一部分是抽象方法时使用.

理由: interface 有多少都可以继承,但class 只有1 个.从1 个开始继承的话,就再也不能继承了,没办法.Abstract class means isA ,interface means like A ;

  •  (六)初始化

不以初始化为目的(参照没有被null初始化).还有,不2度初始化.

坏例子:

class PoorInitialization {
private name = “initial_name”;
public Sample() {
name = “initial_name”;//ERROR
}

                        

理由: 将关于初始化的BUG最小化.

  •  (七)Static和final

static 变量(类变量)要极力避免.(static final 常数除外)

如果实例变量在被作成之后绝对不变化的话,积极使用final .还有,如果不变更方法的自变量的参照地的话,当作final 吧.

理由: final ,synchronization 、编译的効率化等容易被适用.从内部类参照自变量时,有必要是final .

  •  (八)privated和protected

在对象的生命周期要锁定在一定范围时, 尽量用private ,使别人不能破坏 封装性.

理由: private 确实能够Shut Out从类外来的使用,但客户不能凭subclass 化进行细的Chaining.使用protected 以后,发生了变更时继承了它的全类会产生影响

  •  (九)get/set方法

要避免过度作成到实例变量的Access方法getX()/setX() 后当做public .讨论其必要性,做成更有意思的方法.

理由: 实例变量多数依存于其他的实例变量.不能破坏类内部的整合性.

  •  (十)排列声明

排列的声明为Type[] arrayName .

理由: Type arrayName[] 不过是作为从C 那里剩留下的.

例:

static void main(String[] args); --- ○
static void main(String args[]); --- ×

                        
  •  (十一)public方法

类的public 方法以「自动销售机的接口」为目标.设计成容易懂,即使搞错了使用方法,内部的整合性也不会搞坏.还有,如果可能,进行按合同的设计(Design by Contract),用代码表现类的不变条件和方法的事前事后条件.

  •  (十二)this 的return

即使假装考虑了客户的方便,return this 也要尽量避免.

理由:叫做 a.meth1().meth2().meth3() 的连锁一般会成为synchronization上的问题之源

  •  (十三)方法的多重定义

因为自变量的类型,要尽量避免方法的OrverLoad (自变量数不同为OK ).特别是和继承一起使用的话较为麻烦

例:

× : draw(Line), draw(Rectangle)
○ : drawLine(Line), drawRectangle(Rectangle)
○: draw(Shape)

                        

  •  (十四)缺省构造方法

如果可以的话,不管什么时候都准备缺省的构造方法(没有自变量的方法).

理由: 在Class.newInstance() 里从类名字符串可以动态创建该类.

  •  (十五)abstract method in abstract classes

在abstract 类,通过添加no-op方法,并明确声明为abstact 方法.并且,如果可以准备可共有的缺省封装,将其做为protected,使SubClass可在1 行写处理.

理由: 因为java 编译程序在编译时可检出没被封装的abstract 方法,所以可以避免所谓忘记单个封装的Bug.

  •  (十六)object的同值比较

Object的比较是使用equals()方法,不是使用== .而String 的比较必须使用== .

理由: 如果封装者准备了equals(),应该是希望使用使用该方法才封装的.

equals()的缺省的封装,仅仅是==而已.

理由: 在单体测试里,因为assertEquals 使用了equals(),可以简单地写同值测试.

  •  (十七)声明与初始化

Local变量与初始值一起声明.

理由: 最小化变量的假定值.

不好的例子:

void f(int start) {
int i, j; // 无初始值声明
// 多的代码
// ...
i = start + 1;
j = i + 1;
// 使用i, j
}

好的例子:

void f(int start) {
// 多的代码
// ...
// 使用前,首先声明与初始化
int i = start + 1;
int j = i + 1;
// 使用i, j
}

                        
  •  (十八)Local变量的再利用

通过反复使用Local变量,声明新的变量并初始化.

理由: 最小化变量的假定值.

理由: 有助于编译程序的最适化.

不好的例子:

void f(int N, int delta) {
int i; // 无初始值声明
for (i = 0; i < N; i++) {
//使用 i
}
for (i = 0; i < N; i++) {// 还使用i
if (...) {
break;
}
}
if (i != N) { // 判断是否回到最后时使用了i
// ...
}
i = N – delta*2; // 再利用
// ...
}

                        

好例子:

void f(int N, int delta) {
for (int i = 0; i < N; i++) {
// 使用i
}
for (int i = 0; i < N; i++) {
// 使用其他的i
if (...) {
found = true;
break;
}
}
if (found) {
// ...
}
int total = N – delta*2; // 有其他含义的变量
// ...
}

                        

  •  (十九)方法自变量的变更

作为原则,方法的自变量需输入,而不用做输出.即在方法内部不调用变更自变量状态的方法.不在输出自变量里代入新Object(如果可能的话,声明为final).

不好的例子:

void moveX(Point p, int dx) {
p.setX(p.getX()+dx); // 变更自变量(尽量避免)
}
void moveX(Point p, int dx) {
p = new Point(p.getX()+dx, p.getY());
// 这里不传递给调用方
}

                        

例外: 注意性能的情况下

  •  (二十)方法自变量的名字

用来使方法的自变量读取容易.特别在与实例变量重复时,活用this,可以使自变量的读取较为容易.

不好的例子:

void reset(int x_, int y_) {
x = x_;
y = y_;
}
好例子:
void reset(int x, int y) { // 不将自变量名取为x_, y_等
this.x = x;
this.y = y;
}

                        

  •  (二十一)String和基本类型的变换

从int到String或其逆变换,如下(他的基本型也同样).

String s = String.valueOf(i);
int i = Integer.parseInt(s);

                        

理由: 虽有其他的写法,但上述方法最易懂最有效.

其他方法: (不推荐)

String s = “” + i;
String s = new Integer(i).toString();
String s = Integer.toString(i); // 这样不好
int i = new Integer(s).intValue();
int i = Integer.valueOf(s).intValue();

                        

toString() 方法如可能要随时封装.

理由1: 用System.out.println(object)可随时打印.

理由2: 单元测试等失败时的显示比较易懂.

  •  五、注释

  •  (一)Javadoc的活用

java 的注释有3 種:

/** ... */ javadoc 注释.可以html 形式输出文档.

/* */ 通常的注释,内部的

// 通常的注释

内部的public 类,方法,域必须要加/** */ 注释.

  •  (二)长注释

注释跨多行时,应在最初用一句概括,然后后面加长注释.

  •  (三)javadoc TAG

/** */注释中,举从@ 开始的关键字(javadoc TAG).

@author author-name
@param paramName description
@return description of return value
@exception exceptionName description
@see string
@see URL
@see classname#methodname

                        

param, return 中有特別要注意之处,要进行主旨注释.例如,自变量为输出用,被变更时.

例1:

/**
* 取得边界框.
*
* @param b 边界框 (内存与速度効率用,输出自变量)
*/
void getBBox(BBox b) { b.min = this.min; b.max = this.max; }
                        
  •  (四)类注释

/** */ 注释,用于机能概要,即外部的规格描述,写在类及方法的定义开始前.该注释的第1 行有特別处理.即,被html 的Method Index使用.因此,最初的1 行应是注释対象的外部的机能的简短説明.该行以,半角(.),或
HTML TAG结束.接该第1 行,进行机能説明.

注释中,,写使用例等时,也可用

 
围住自動缩排,而避免改行.

  •  (五)// vs. /* */

方法或类的内部注释要使用/* */ 或// ,可根据长度判断.

1 行注释最好用//.

例1:

/*
* 作用:
* 1. do something
* 2. do something
* 3. do somethng
*/

                        

例2:

int index = -1; // -1 验证值的意思
                        

参考: 这个方法最好

static final int INVALID= -1;
int index = INVALID;