后台编码规范
-
一、 方针
此编码标准是在软件开发,提供用java 编码时的规则,推荐,以及困惑时的查询。标准制定的方针是写容易读,容易维护的代码。在实际的编码中,需要项目组成员全体遵守此规则。
-
二、文件构成
-
(一)文件名
public 类要当作其类名的1个文件.
例: public class Point 要放到Point.java 中
软件包内的非Public类包含在其类被主要使用的Public类的文件中为好(此时,要注意*.java 和*.class 不对应).
-
(二)文件的位置
决定Project的根目录,将软件包名的“.”放入置换到目录阶层的位置中.
例: 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
建议在实际的项目中,包的命名由项目经理和开发组长来制定,在整个项目中使用统一的包名及类名。结合本公司的实际,制定一个参考如下(都位于
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;