Java 代码规范

Java代码规范

本Java代码规范以SUN的标准Java代码规范为基础,为适应我们公司的实际需要,可能会做一些修改。本文档中没有说明的地方,请参看SUN Java标准代码规范。如果两边有冲突,以本文档为准。

1. 标识符命名规范

1.1 概述

标识符的命名力求做到统一、达意和简洁。

1.1.1 统一

统一是指,对于同一个概念,在程序中用同一种表示方法,比如对于供应商,既可以用supplier,也可以用provider,但是我们只能选定一个使用,至少在一个Java项目中保持统一。统一是作为重要的,如果对同一概念有不同的表示方法,会使代码混乱难以理解。即使不能取得好的名称,但是只要统一,阅读起来也不会太困难,因为阅读者只要理解一次。

1.1.2 达意

达意是指,标识符能准确的表达出它所代表的意义,比如: newSupplier, OrderPaymentGatewayService等;而 supplier1, service2,idtts等则不是好的命名方式。准确有两成含义,一是正确,而是丰富。如果给一个代表供应商的变量起名是 order,显然没有正确表达。同样的,supplier1, 远没有targetSupplier意义丰富。

1.1.3 简洁

简洁是指,在统一和达意的前提下,用尽量少的标识符。如果不能达意,宁愿不要简洁。比如:theOrderNameOfTheTargetSupplierWhichIsTransfered 太长, transferedTargetSupplierOrderName则较好,但是transTgtSplOrdNm就不好了。省略元音的缩写方式不要使用,我们的英语往往还没有好到看得懂奇怪的缩写。

1.1.4 骆驼法则

Java中,除了包名,静态常量等特殊情况,大部分情况下标识符使用骆驼法则,即单词之间不使用特殊符号分割,而是通过首字母大写来分割。比如: SupplierName, addNewContract,而不是 supplier_name, add_new_contract。

1.1.5 英文 vs 拼音

尽量使用通俗易懂的英文单词,如果不会可以向队友求助,实在不行则使用汉语拼音,避免拼音与英文混用。比如表示归档,用archive比较好, 用pigeonhole则不好,用guiDang尚可接受。

1.2 包名

使用小写字母如 com.xxx.settlment,不要 com.xxx.Settlement
单词间不要用字符隔开,比如 com.xxx.settlment.jsfutil,而不要com.xxx.settlement.jsf_util

1.3 类名

1.3.1 首字母大写

类名要首字母大写,比如 SupplierService, PaymentOrderAction;不要 supplierService, paymentOrderAction.

1.3.2 后缀

类名往往用不同的后缀表达额外的意思,如下表:

后缀名意义举例
Service表明这个类是个服务类,里面包含了给其他类提同业务服务的方法PaymentOrderService
Impl这个类是一个实现类,而不是接口PaymentOrderServiceImpl
Inter这个类是一个接口LifeCycleInter
Dao这个类封装了数据访问方法PaymentOrderDao
Action直接处理页面请求,管理页面逻辑了类UpdateOrderListAction
Listener响应某种事件的类PaymentSuccessListener
Event这个类代表了某种事件PaymentSuccessEvent
Servlet一个ServletPaymentCallbackServlet
Factory生成某种对象工厂的类PaymentOrderFactory
Adapter用来连接某种以前不被支持的对象的类DatabaseLogAdapter
Job某种按时间运行的任务PaymentOrderCancelJob
Wrapper这是一个包装类,为了给某个类提供没有的能力SelectableOrderListWrapper
Bean这是一个POJOMenuStateBean

1.4 方法名

首字母小写,如 addOrder() 不要 AddOrder()
动词在前,如 addOrder(),不要orderAdd()
动词前缀往往表达特定的含义,如下表:

前缀名意义举例
create创建createOrder()
delete删除deleteOrder()
add创建,暗示新创建的对象属于某个集合addPaidOrder()
remove删除removeOrder()
init或则initialize初始化,暗示会做些诸如获取资源等特殊动作initializeObjectPool
destroy销毁,暗示会做些诸如释放资源的特殊动作destroyObjectPool
open打开openConnection()
close关闭closeConnection()<
read读取readUserName()
write写入writeUserName()
get获得getName()
set设置setName()
prepare准备prepareOrderList()
copy复制copyCustomerList()
modity修改modifyActualTotalAmount()
calculate数值计算calculateCommission()
do执行某个过程或流程doOrderCancelJob()
dispatch判断程序流程转向dispatchUserRequest()
start开始startOrderProcessing()
stop结束stopOrderProcessing()
send发送某个消息或事件sendOrderPaidMessage()
receive接受消息或时间receiveOrderPaidMessgae()
respond响应用户动作responseOrderListItemClicked()
find查找对象findNewSupplier()
update更新对象updateCommission()

find方法在业务层尽量表达业务含义,比如 findUnsettledOrders(),查询未结算订单,而不要findOrdersByStatus()。 数据访问层,find,update等方法可以表达要执行的sql,比如findByStatusAndSupplierIdOrderByName(Status.PAID, 345)

1.5 域(field)名

1.5.1 静态常量

全大写用下划线分割,如


public static find String ORDER_PAID_EVENT = "ORDER_PAID_EVENT";

1.5.2 枚举

全大写,用下划线分割,如

public enum Events {
ORDER_PAID,
ORDER_CREATED
}

1.5.3 其他

首字母小写,骆驼法则,如:

public String orderName;

1.6 局部变量名

参数和局部变量名首字母小写,骆驼法则。尽量不要和域冲突,尽量表达这个变量在方法中的意义。

2. 代码格式

用空格字符缩进源代码,不要用tab,每个缩进4个空格。

2.1 源文件编码

源文件使用utf-8编码,结尾用unix n 分格。

2.2 行宽

行宽度不要超过130。

2.3 包的导入

删除不用的导入,尽量不要使用整个包的导入。在eclipse下经常使用快捷键 ctrl+shift+o 修正导入。

2.4 类格式

2.5 域格式

每行只能声明一个域。
域的声明用空行隔开。

2.5 方法格式

2.6 代码块格式

2.6.1 缩进风格

大括号的开始在代码块开始的行尾,闭合在和代码块同一缩进的行首,例如:

package com.test;

public class TestStyle extends SomeClass implements AppleInter, BananaInter {
public static final String THIS_IS_CONST = "CONST VALUE";

private static void main(String[] args) {
int localVariable = 0;
}

public void compute(String arg) {
if (arg.length() > 0) {
System.out.println(arg);
}

for (int i = 0; i < 10; i++) {
System.out.println(arg);
}

while (condition) {

}

do {
otherMethod();
} while (condition);

switch (i) {
case 0:
callFunction();
break;
case 1:
callFunctionb();
break;
default:
break;
}
}
}

2.6.2 空格的使用
2.6.2.1 表示分割时用一个空格

不能这样:

if ( a > b ) {
//do something here
};

2.6.2.2 二元三元运算符两边用一个空格隔开

如下:

a + b = c;
b - d = e;
return a == b ? 1 : 0;

不能如下:


a+b=c;
b-d=e;
return a==b?1:0;

2.6.2.3 逗号语句后如不还行,紧跟一个空格

如下:

call(a, b, c);

不能如下:

call(a,b,c);

2.6.3 空行的使用

空行可以表达代码在语义上的分割,注释的作用范围,等等。将类似操作,或一组操作放在一起不用空行隔开,而用空行隔开不同组的代码, 如图:

order = orderDao.findOrderById(id);

//update properties
order.setUserName(userName);
order.setPrice(456);
order.setStatus(PAID);

orderService.updateTotalAmount(order);

session.saveOrUpdate(order);

上例中的空行,使注释的作用域很明显.

  • 连续两行的空行代表更大的语义分割。
  • 方法之间用空行分割
  • 域之间用空行分割
  • 超过十行的代码如果还不用空行分割,就会增加阅读困难

3. 注释规范

3.1 注释 vs 代码

  • 注释宜少二精,不宜多而滥,更不能误导
  • 命名达意,结构清晰, 类和方法等责任明确,往往不需要,或者只需要很少注释,就可以让人读懂;相反,代码混乱,再多的注释都不能弥补。所以,应当先在代码本身下功夫。
  • 不能正确表达代码意义的注释,只会损害代码的可读性。
  • 过于详细的注释,对显而易见的代码添加的注释,罗嗦的注释,还不如不写

  • 注释要和代码同步,过多的注释会成为开发的负担
  • 注释不是用来管理代码版本的,如果有代码不要了,直接删除,svn会有记录的,不要注释掉,否则以后没人知道那段注释掉的代码该不该删除。

3.2 Java Doc

表明类、域和方法等的意义和用法等的注释,要以javadoc的方式来写。Java Doc是个类的使用者来看的,主要介绍 是什么,怎么用等信息。凡是类的使用者需要知道,都要用Java Doc 来写。非Java Doc的注释,往往是个代码的维护者看的,着重告述读者为什么这样写,如何修改,注意什么问题等。 如下:

/**
* This is a class comment
*/
public class TestClass {
/**
* This is a field comment
*/
public String name;

/**
* This is a method comment
*/
public void call() {

}
}

3.3 块级别注释

3.3.1 块级别注释,单行时用 //, 多行时用 /* .. */。
3.3.2 较短的代码块用空行表示注释作用域
3.3.3 较长的代码块要用


/*------ start: ------*/

/*-------- end: -------*/

包围
如:

/*----------start: 订单处理 ------- */
//取得dao
OrderDao dao = Factory.getDao("OrderDao");

/* 查询订单 */
Order order = dao.findById(456);

//更新订单
order.setUserName("uu");
order.setPassword("pass");
order.setPrice("ddd");

orderDao.save(order);
/*----------end: 订单处理 ------- */

3.3.4 可以考虑使用大括号来表示注释范围

使用大括号表示注释作用范围的例子:

/*----------订单处理 ------- */
{
//取得dao
OrderDao dao = Factory.getDao("OrderDao");

/* 查询订单 */
Order order = dao.findById(456);

//更新订单
order.setUserName("uu");
order.setPassword("pass");
order.setPrice("ddd");

orderDao.save(order);
}

3.4 行内注释

行内注释用 // 写在行尾

4 最佳实践和禁忌

4.1 每次保存的时候,都让你的代码是最美的

程序员都是懒惰的,不要想着等我完成了功能,再来优化代码的格式和结构,等真的把功能完成,很少有人会再愿意回头调整代码。

4.2 使用log而不是System.out.println()

log可以设定级别,可以控制输出到哪里,容易区分是在代码的什么地方打印的,而System.out.print则不行。而且,System.out.print的速度很慢。所以,除非是有意的,否则,都要用log。至少在提交到svn之前把System.out.print换成log。

4.3 每个if while for等语句,都不要省略大括号{}

看下面的代码:

if (a > b)
a++;

如果在以后维护的时候,需要在a > b 时,把b++,一步小心就会写成:

if (a > b)
a++;
b++;

这样就错了,因为无论a和b是什么关系,b++都会执行。 如果一开始就这样写:

if (a > b) {
a++;
}

相信没有哪个笨蛋会把b++添加错的。而且,这个大括号使作用范围更明显,尤其是后面那行很长要折行时。

4.4 善用TODO:

在代码中加入 //TODO: ,大部分的ide都会帮你提示,让你知道你还有什么事没有做。比如:

if (order.isPaid()) {
//TODO: 更新订单
}

4.5 在需要留空的地方放一个空语句或注释,告述读者,你是故意的

比如:

if (!exists(order)) {
;
}

或:


if (!exists(order)) {
//nothing to do
}

4.6 不要再对boolean值做true false判断

比如:

if (order.isPaid() == true) {
// Do something here
}

不如写成:

if (order.isPaid()) {
//Do something here
}

后者读起来就很是 if order is paid, .... 要比 if order's isPaid method returns true, … 更容易理解

4.7 减少代码嵌套层次

代码嵌套层次达3层以上时,一般人理解起来都会困难。下面的代码是一个简单的例子:

public void demo(int a, int b, int c) {
if (a > b) {
if (b > c) {
doJobA();
} else if (b < c) {
doJobB()
}
} else {
if (b > c) {
if (a < c) {
doJobC();
}
}
}
}

减少嵌套的方法有很多:

  • 合并条件
  • 利用 return 以省略后面的else
  • 利用子方法

比如上例,合并条件后成为:

public void demo(int a, int b, int c) {
if (a > b && b > c) {
doJobA();
}
if (a > b && c > b) {
doJobB();
}
if (a <= b && c < b && a < c) {
doJobC();
}
}

如果利用return 则成为:

public void demo(int a, int b, int c) {
if (a > b) {
if (b > c) {
doJobA();
return;
}
doJobB()
return;
}

if (b > c) {
if (a < c) {
doJobC();
}
}
}

利用子方法,就是将嵌套的程序提取出来放到另外的方法里。

4.8 程序职责单一

关注点分离是软件开发的真理。人类自所以能够完成复杂的工作,就是因为人类能够将工作分解到较小级别的任务上,在做每个任务时关注更少的东西。让程序单元的职责单一,可以使你在编写这段程序时关注更少的东西,从而降低难度,减少出错。

4.9 变量的声明,初始化和被使用尽量放到一起

比方说如下代码:

int orderNum= getOrderNum();

//do something withou orderNum here

call(orderNum);

上例中的注释处代表了一段和orderNum不相关的代码。orderNum的声明和初始化离被使用的地方相隔了很多行的代码,这样做不好,不如这样:

//do something withou orderNum here

int orderNum= getOrderNum();
call(orderNum);

4.10 缩小变量的作用域

能用局部变量的,不要使用实例变量,能用实例变量的,不要使用类变量。变量的生存期越短,以为着它被误用的机会越小,同一时刻程序员要关注的变量的状态越少。实例变量和类变量默认都不是线程安全的,局部变量是线程安全的。比如如下代码:

public class OrderPayAction{
private Order order;

public void doAction() {
order = orderDao.findOrder();
doJob1();
doJob2();
}

private void doJob1() {
doSomething(order);
}

private void doJob2() {
doOtherThing(order);
}
}

上例中order只不过担当了在方法间传递参数之用,用下面的方法更好:

public class OrderPayAction{

public void doAction() {
order = orderDao.findOrder();
doJob1(order);
doJob2(order);
}

private void doJob1(Order order) {
doSomething(order);
}

private void doJob2(Order order) {
doOtherThing(order);
}
}

4.11 尽量不要用参数来带回方法运算结果

比如:

public void calculate(Order order) {
int result = 0;
//do lots of computing and store it in the result

order.setResult(result);
}

public void action() {
order = orderDao.findOrder();
calculate(order);

// do lots of things about order
}

例子中calculate方法通过传入的order对象来存储结果, 不如如下写:

public int calculate(Order order) {
int result = 0;
//do lots of computing and store it in the result

return result;
}

public void action() {
order = orderDao.findOrder();
order.setResult(calculate(order));

// do lots of things about order
}

代码规范比比皆是,但是很少有公司做好代码规范的。忍不住想谈谈代码规范的重要性,希望所有人都能够重视起来。而且,我相信,如果我们代码规范能够做好的话,且不说开发水平提高多少,至少我们也会有很多出色开源项目。 一、规范代码可以促进团队合作 一个项目大多都是由一个团队来完成,如果没有统一的代码规范,那么每个人的代码必定会风格迥异。且不说会存在多个人同时开发同一模块的情况,即使是分工十分明晰的,等到要整合代码的时候也有够头疼的了。大多数情况下,并非程序中有复杂的算法或是复杂的逻辑,而是去读别人的代码实在是一件痛苦的事情。统一的风格使得代码可读性大大提高了,人们看到任何一段代码都会觉得异常熟悉。显然的,规范代码在团队的合作开发中是非常有益而且必要的。 二、规范代码可以减少bug处理 很多IT人士将程序员比做民工,这也的确非常的形象。就像刚才提到的,复杂的算法或逻辑只占项目中很小的比例,大多仅仅是垒代码的工作。可是越是简单,测试的bug反而是越多,而且是无穷无尽的bug。这里很大的程度上是由于代码规范所致。 没有规范的对输入输出参数的规范,没有规范的异常处理,没有规范的日志处理等等,不但导致了我们总是出现类似空指针这样低级的bug而且还很难找到引起bug的原因。相反,在规范的开发中,bug不但可以有效减少,查找bug也变得轻而易举。 规范不是对开发的制约,而确实是有助于提高开发效率的。 三、规范代码可以降低维护成本 随着我们项目经验的累积,会越来越重视后期维护的成本。而开发过程中的代码质量直接影响着维护的成本。因此,我们不得不从开发时便小心翼翼。 在第一点中曾提到,规范代码大大提高了程序的可读性,几乎所有的程序员都曾做过维护的工作,不用多说,可读性高的代码维护成本必然会大大降低。 但是,维护工作不仅仅是读懂原有代码,而是需要在原有代码基础上作出修改。我们可以先想像没有统一风格的情况下,A完成开发以后,B进行维护加一段代码,过一段时间C又加一段代码。。。。。。直到有一天X看到那一大堆乱码想死的心都有了,维护也就进行不下去了。因此,统一的风格有利于长期的维护。 另外,好的代码规范会对方法的度量、类的度量以及程序耦合性作出约束。这样不会出现需要修改一个上千行的方法或者去扩展一个没有接口的类的情况。规范代码对程序的扩展性提高,无疑也是对维护人员的一个奖励。 四、规范代码有助于代码审查 我个人是比较赞同进行代码审查的,这样可以及时纠正一些错误,而且可以对开发人员的代码规范作出监督。团队的代码审查同时也是一个很好的学习机会,对成员的进步也是很有益的。但是,开发随意,加重的代码审查的工作量及难度,并且使得代码审查工作没有根据,浪费了大量的时间却收效甚微。 代码规范不仅使得开发统一,减少审查拿督,而且让代码审查有据可查,大大提高了审查效率和效果,同时代码审查也有助于代码规范的实施。一举多得,何乐而不为呢。 五、养成代码规范的习惯,有助于程序员自身的成长 即使明白代码规范的好处,但是有的迫于项目压力,有的因为繁琐的规范作出很多额外的工作,更有的不重视维护的问题,而很难贯彻代码规范。 那么,我们需要了解,规范开发最大的受益人其实是自己! 你有没有花费很多的时候查找自己的代码呢?尤其是出现bug的时候需要逐行的debug?自己写的代码乱了头绪的确实也见了不少。我们应该做的就是规范开发,减少自己出现的错误。很多时候项目的压力一部分也是由于前期开发中遗留的众多的问题。 还有的人觉得自己可以完成高难度的算法,就认为自己能力很强,不把规范放在眼里。很多人确实是这样,追求个性,大概让别人看他的代码一头雾水更觉得得意。殊不知复杂的算法确实可以体现你个人的逻辑能力,但是绝不代表你的开发水平。我们知道一些开源项目,一些大师级人物写得程序都是极其规范的。并非规范了就代表高水平,实际上是规范代码更有利于帮助你理解开发语言理解模式理解架构,能够帮助你快速提升开发水平。不明白这点,即使你写的再高明的算法,没准哪天也被当作乱码别处理掉。 记住!每天垒乱码(或许你不觉得,但是大多时候在别人眼中确实就是乱码)并不能使你获得更多的进步,相反要达到高水平的程序员,养成良好的开发习惯是绝对必需的。 不要沉迷表面的得失,看似无用的东西要经过慢慢的累积由量变达到质变的时候,你才能感受到其价值所在。 最后提醒一句,制定一个符合自己公司情况的开发规范是很简单的,重要的是我们能够认识到规范的重要性,并坚持规范的开发习惯。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值