Java编码规范V1.0

 Java编码规范V1.0

 

 

1 代码总体原则

1. 清晰第一

清晰性是易于维护、易于重构的程序必需具备的特征。代码首先

是给人读的,其次才给机器用来执行。

目前软件维护期成本占整个生命周期成本的 40%~90%。根据业界经

验,维护期变更代码的成本,小型系统是开发期的 5 倍,大型系统

100 万行代码以上)可以达到 100 倍。业界的调查指出,开发组平

均大约一半的人力用于弥补过去的错误,而不是添加新的功能来帮助

公司提高竞争力。可见代码清晰的重要。

2. 简洁为美

简洁就是易于理解并且易于实现。代码越长越难以看懂,也就越容易

在修改时引入错误。写的代码越多,意味着出错的地方越多,也就意

味着代码的可靠性越低。因此,我们提倡大家通过编写简洁明了的代

码来提升代码可靠性。废弃的代码(没有被调用的函数和全局变量)

要及时清除,重复代码应该尽可能提炼成函数。

3. 风格一致

产品所有人共同分享同一种风格所带来的好处,远远超出为了统

一而付出的代价。在公司编码规范的指导下,审慎地编排代码以使代

码尽可能清晰,是一项非常重要的技能。新的源文件使用新的规则编

码代码,老的源文件代码修改可以继续沿用老规则。

 

 

2 术语定义

【原则】:编程时必须坚持的指导思想。

【规则】:编程时强制必须遵守的约定。

【建议】:编程时必须加以考虑的约定。

3 范围

本规范制定了编写 JAVA 语言程序的基本原则、规则和建议。

本规范适用于公司内使用 JAVA 语言编码的所有软件/项目。本规

范自发布之日起生效,对以后新编写的代码应遵守本规范。老的源文

件代码修改可以继续沿用老规则。

本规范实施中遇到问题,可以反馈给海报中说明的人员。

在某些情况下需要违反本文档给出的规则时,相关团队必须通过

一个正式的流程来评审、决策规则违反的部分。

4 代码排版

【规则 1.1】源文件字符编码统一为 UTF-8

【规则 1.2】代码块要按层级缩进,缩进为 4 个空格。

每当开始一个新的块,缩进增加 4 个空格,当块结束时,缩进返

回先前的缩进级别。

缩进级别适用于代码和注释。

不要使用 Tab 缩进,因为在不同的编辑器下 Tab 的宽度不一致。

Tip:目前主流编辑器/IDE 都支持将 Tab 自动转换成空格输入,

需打开相应功能设置。

【规则 1.3】一行不能写多条语句,即一行一条语句。

示例:以下不规范

int a = 0; int b = 1;

应该改成:

int a = 0;

int b = 1;

【规则 1.4】一行代码超过 120 个字符要换行。

换行时有如下建议: 

1. 换行时要增加一级缩进,连续换行只需要第一次换行进行缩

进; 

2. 在低优先级操作符处断行;操作符放在新行首;

Tip:在 Eclipse 环境下使用 Ctrl+Shift+F 快捷键进行代码格式

化时会对长行自动进行换行。

【规则 1.5】大括号遵循 K&R 风格,左括号前不换行,左大括号后

换行;右大括号前换行,如果右大括号是一个语句、函数体或类的

终止,则右大括号后换行,否则不换行。例如,如果右大括号后面

else 或逗号,则不换行。 

 

示例:

public void method() {

    if (condition()) {

        // … statement

    } else {

        // … statement

    }

}

一个空的块状结构里什么也不包含,大括号可以简洁地写成{}

不需要换行。

示例:

void doSomeThing() {}

【规则 1.6】不能省略大括号

大括号与 if, else, for, do, while, switch, case, default

语句一起使用,即使只有一条语句也要把大括号写上。

示例:以下代码在维护时极易引起 bug

if (test()) 

    doSomeThing();

应该写成:

if (test()) {

    doSomeThing();

}

【建议 1.1】在操作符前后加空格。

1. 逗号只在后面加空格。

示例:

int a, b, c; 

2. 比较操作符, 赋值操作符"=" "+=",算术操作符"+"

"%",逻辑操作符"&&""&",位域操作符"<<""^"等双目操

作符在前后加空格。

示例:

a = b + c;

a *= 2;

a = b ^ 2;

3. "!""~""++""--"等单目操作符前后不加空格。

示例:

flag = !isEmpty; // 非操作"!"与内容之间

i++;          // "++","--"与内容之间

4. "."前后不加空格。

示例:

p.id = pid;     // "."前后不加空格

5. ifforwhileswitch 等与后面的括号间应加空格。 

示例:

if (a >= b && c > d)

 【建议 1.2】每个类应该以某种逻辑去排序它的成员和方法,维护

者应该要能解释这种排序逻辑。

【建议 1.3】重载:永不分离

当一个类有多个构造函数,或是多个同名方法,这些函数/方法应

该按顺序出现在一起,中间不要放进其它函数/方法。

5 命名

Java 语言较多使用驼峰式命名法,有以下 2 种区分:

大驼峰:各单词连接起来书写,每个单词的首字母大写,其余字

母小写。例如:OrderItem

小驼峰:在大驼峰的基础上将第一个单词的首字母改为小写。例

如:orderItem

【原则 2.1 标识符的命名要清晰、明了,有明确含义,同时使用

完整的单词或大家基本可以理解的缩写,避免使人产生误解。 

【原则 2.2 除了常见的通用缩写以外,不使用单词缩写,不得使

用汉语拼音。

当标识符过长时,可通过去掉“元音”形成缩写,或采用大家公

认的缩写,常用单词的缩写必须统一。

示例:一些常见可以缩写的例子: 

argument 可缩写为 arg 

 buffer 可缩写为 buff 

command 可缩写为 cmd 

compare 可缩写为 cmp 

configuration 可缩写为 cfg 

error 可缩写为 err 

increment 可缩写为 inc 

initialize 可缩写为 init 

maximum 可缩写为 max 

minimum 可缩写为 min 

message 可缩写为 msg 

previous 可缩写为 prev 

password 可缩写为 pwd

【规则 2.1】包名使用倒置的域名形式,全部采用小写字母,连续

的单词只是简单地连接起来,不使用下划线。

参考格式:com.cmcc.工程代号.模块名。

【规则 2.2】类名和接口名使用有意义的英文单词或简写,以大驼

峰风格编写。一般是名词或名词短语。

示例:

public interface MailSender

public class SmtpMailSender implements MailSender

 【规则 2.3】测试类的命名以它要测试的类的名称开始,以 Test

束。

示例:

public class SmtpMailSenderTest

【规则 2.4】常量名命名模式为 CONSTANT_CASE,全部字母大写,用

下划线分隔单词,并带上 static final 修饰符。

示例:

private static final int DEFAULT_PORT = 25;

【规则 2.5】属性名使用有意义的英文单词或简写,以小驼峰风格

编写。一般是名词或名词短语。

【规则 2.6】方法名使用有意义的英文单词或简写,以小驼峰风格

编写。一般是动词或动词短语,在同一个类中,方法名和属性名不

能相同。

【规则 2.7boolean 类型属性的 getter 方法使用 is + 布尔属性

()

示例:以下不规范

private boolean isClosed;

public boolean getIsClosed() {

    return isClosed;

}

 应该写成:

private boolean closed;

public boolean isClosed() {

    return closed;

}

【规则 2.8】参数名、局部变量名使用有意义的英文单词或简写,

以小驼峰风格编写。

【建议 2.1】含有集合意义的属性命名,尽量包含其复数的意义。

示例:

private List<Item> items;

【建议 2.2】局部变量名尽量不与类成员属性名相同。

【建议 2.3】尽量控制名称标识在 15 个字母以内,如果名称过长,

可参考【原则 2.2】的方法进行缩写。

6 设计

【原则 3.1】明确接口和类的功能,精确地实现接口和类设计。一

个接口和类包含一组相近的功能。不要设计面面俱到的接口和类。

 

 

【原则 3.2】以最小公开原则使用访问修饰符,不是必须使用

public 的,考虑使用 protected;不是必须使用 protected 的,考

虑使用 private

【原则 3.3】一个函数仅完成一件功能,重复代码尽可能提炼成函

数。

【规则 3.1】接口方法和 public 方法要声明该方法的作用,每个输

入参数的规范、函数返回值、以及哪种情况下会抛出哪种业务异

常。

通常以 Javadoc 注释的形式进行以上声明。如果可以,考虑为参

数设置默认值,以增加程序健壮性,但要在 Javadoc 注释中写明。

在接口的实现类中不用再次对该方法进行相应说明。

【规则 3.2】数据类要实现 java.io.Serializable 接口,便于序列

化后存储或传输。

【规则 3.3】对输入参数进行校验,程序不因传入错误数据而被破

坏。

接口设计时已经明确规定各输入参数的合法形式,因此调用者在

调用该方法前应进行相应参数检查。

这并不意味接口实现者无需进行参数检查,接口实现者为保护自

己的程序,仍然需要进行参数检查,如果传入非法参数,可抛出

IllegalArgumentException 异常,终止函数执行。在确保传入非法参

 数时该方法会异常退出且不造成任何副作用的情况下,可不必对参数

进行显示的检查。

private 方法因在内部调用,调用者清楚其行为,不必在该方法体

中对参数进行显示检查。

【规则 3.4】在程序中使用业务异常来返回错误而不要使用错误

码。

针对每种业务错误都应该定义一个业务异常类与之对应,业务异

常继承自 java.lang.Exception

要严格区分业务异常和系统异常。

业务异常是那些有理由能“预见”的异常情况,例如:用户转账

的金额超过账户余额。业务异常归类为受检异常。

除业务异常外,其它异常都是不应该发生的异常,称为系统异常,

一般是因为编程错误或者系统环境故障引起的。系统异常归类为运行

时异常。

Tip 如果担 使

fillInStackTrace 方法。

【规则 3.5】在顶层应用程序代码中,所有的异常都要最终得到处

理,至少要日志记录详细的异常信息。

例如:在 Runnable 类中的 run 方法中,要 catch 所有异常进行

处理。

【规则 3.6】抛出异常时必须要填写异常的原因。

 

【规则 3.7】日志输出要正确对待 log 级别:debug 打印跟踪调试信

息;info 通常打印有意义的业务信息;warn 表明系统检查到了一些

错误,但仍然可以恢复运行;error 表明出现了一些非预期的异

常,无法确定是否能恢复正常运行。

【建议 3.1】一个接口包含的方法在 10 个以内,如果超过,需考虑

是否需要拆分。

【建议 3.2】控制单个函数代码行数在 30 行以内,缩进层次不超过

3 层。

【建议 3.3】明确哪些异常是当前应该捕获并处理的,在处理前,

典型的方式是打印日志。如果该异常被认为是不可能的,则把它作

为一个运行期异常重新抛出;如果它确实是可忽略的,不需要在

catch 块中做任何响应,需要注释加以说明。

示例:无需做出响应的异常

try {

    int i = Integer.parseInt(response);

    return handleNumericResponse(i);

} catch (NumberFormatException ok) {

    // it's not numeric; that's fine, just continue

}

return handleTextResponse(response);

 【建议3.4】不要捕获不知道该如何处理的异常,如果确实捕获到

了,记录日志后重新抛出。

因为你的上层代码可能会很好地处理该异常,因此最好不要捕获。

【建议 3.5】区分一个接口方法是命令(Command)还是查询

Query ,如果是查询,确保其实现不产生副作用。

查询:当一个方法返回一个值来回应一个问题的时候,它就具有

查询的性质。

命令:当一个方法要改变对象的状态的时候,它就具有命令的性

质。

通常,一个方法可能是纯的Command模式或者是纯的Query模式,

或者是两者的混合体。

在设计接口时,如果可能,应该尽量使接口单一化,保证方法的

行为严格的是命令或者是查询。这样查询方法不会改变对象的状态,

没有副作用。例如,在 java.util.Iterator 中,hasNext 可以被看作

一种查询,remove 是一种命令,next 合并了命令和查询。

【建议 3.6】数据类尽量覆写 toString() 方法,返回该类有意义的

内容,一般为各属性的字符串拼接,便于调试时打印输出。

【建议 3.7】一个方法不应声明抛出太多类型的异常。

如果程序中需要分类处理,则将异常根据分类组织成继承关系。

throws/exception 子句标明的异常最好不要超过三个。

 【建议 3.8】为方便调试,应在函数的入口,每个分支都打印 debug

日志,日志信息包含主要的参数值。

7 编码

【规则 4.1】不要 import 无用的类和接口,import 不要使用通配

符。

【规则 4.2】不要定义不会被用到的局部变量、类私有属性、类私

有方法。

【规则 4.3】变量在使用时才进行定义,并尽快初始化。

【规则 4.4】在一个 switch 块内,每个语句组要么通过 break,

continue, return 或抛出异常来终止,要么通过一条注释来说明程

序将继续执行到下一个语句组,每个 switch 语句都包含一个

default 语句组,即使它什么代码也不包含。

示例:

switch (input) {

    case 1: {}

    case 2: {

        prepareOneOrTwo();  // fall through

    }

    case 3: {

         handleOneTwoOrThree();

        break;

    }

    default: {

        handleLargeNumber(input);

    }

}

【规则 4.5】注意运算符的优先级,并用括号明确表达式的操作顺

序,避免使用默认优先级。

防止阅读程序时产生误解,防止因默认的优先级与设计思想不符

而导致程序出错。即使你非常清楚 java 的优先级规则也应该这样做。

【规则 4.6】数组声明的时候使用 int[] array,不要使用 int

array[]。中括号是类型的一部分。

【规则 4.7】生产代码中禁用 System.out System.err 进行打

印,一律使用 Log 框架打印。

【规则 4.8】数据库、IO 等资源操作在使用完后必须在 try

catch-finally finally 块中调用 close()方法释放资源,不能

在循环体中建立数据库等资源的链接。

【规则 4.9 使用 Jdbc 访问数据库时使用 PreparedStatement

定变量执行,不得使用字符串连接拼装 SQL 查询条件。

 

 

字符串连接拼装 SQL 容易产生 SQL 注入漏洞,要避免。

【规则 4.10】静态成员或者方法使用类名访问,不使用句柄访问。

【规则 4.11】不要在日志中打印出用户密码以及其它涉及机密数据

的信息。

【规则 4.12】字符串比较使用 equals 方法,调用 equals 之前确认

其不可能为 null

示例:在 equals 调用前确认其不为 null

if (name != null && name.equals(“admin”))

【建议 4.1】不要使用过期的类或方法,寻找并使用该类或方法的

替代品。

【建议 4.2】注意开发工具的警告信息,尽量将警告消灭掉。

【建议 4.3】在运算中注意数据类型和隐式转换,不要减小数据的

精度。

【建议 4.4】初始化集合时设置集合的容量大小。集合中的数据如

果不使用了应该及时释放,尤其是可重复使用的集合。

由于集合保存了对象的句柄,虚拟机的垃圾收集器就不会回收。

初始化集合大小是为了避免集合频繁地扩容。

【建议 4.5】源程序中关系较为紧密的代码应尽可能相邻。

 

 

示例:矩形的长与宽关系较密切,放在一起。 

rect.length = 10;

rect.width = 5;

8 注释

【原则 5.1 优秀的代码可以自我解释,不通过注释即可轻易读

懂,不言自明的代码不用加以注释。

清晰准确的函数、变量等命名以及合理地组织代码的结构,可增

加代码可读性,使代码成为自注释的。

【原则 5.2】注释的内容要清楚、明了,含义准确,防止注释二义

性。 

不准确和有歧义和的注释不但无益反而有害。

【原则 5.3 在代码的功能、意图层次上进行注释,即注释解释代

码难以直接表达的意图,而不是重复描述代码。 

注释的目的是解释代码的目的、功能和采用的方法,提供代码以

外的信息,帮助读者理解代码,防止没必要的重复注释信息。对于实

现代码中巧妙的、晦涩的、有趣的、重要的地方加以注释。 

注释不是为了名词解释(what),而是说明用途(why)。 

示例:如下注释没有意义,不如不写。

// 如果 receiveFlag 为真

if (receiveFlag) { 

 

 

而如下的注释则给出了额外有用的信息。

// 如果收到消息

if (receiveFlag) { 

【规则 5.1】类和接口注释、成员属性注释、public 方法注释使用

Javadoc 形式。

【规则 5.2】成员属性注释,除非不言自明,否则必须要添加注

释,描述该属性的意义和作用,以及可能被用到的地方。

示例:

/** 用户状态,取值(0:未激活,1:正常,2:锁定)*/

private String userStatus;

【规则 5.3】公有方法注释,描述该方法的主要功能、输入参数、

返回值、异常情况等。

参考格式:

/**

 * 〈功能简述〉

 * @param  [参数 1]   [说明参数规范,默认值等]

 * @param  [参数 2]   [参数 2 说明]

 * @return [说明各种情况下应该会返回什么值]

 * @throws [异常类型 1] [说明哪种情况会抛出该异常

 * @throws [异常类型 2] [说明哪种情况会抛出该异常]

 */

 

 

对于可能抛出的 RuntimeException,可不必进行说明。

示例:摘自 java.lang.CharSequence

/**

 * Returns the char value at the specified index. An index

ranges from zero to length() - 1.

 * The first char value of the sequence is at index zero,

the next at index one, and so on, as for array indexing.

 * If the char value specified by the index is a surrogate

the surrogate

 * value is returned.

 *

 * @param  index  the index of the char value to be

returned

 * @return  the specified char value

 * @throws  IndexOutOfBoundsException

 *          if the index argument is negative or not less

than length()

 */

 char charAt(int index);

【规则 5.4】注释应与其描述的代码相近,对代码的注释应放在其

上方或右方(对单条语句的注释)相邻位置,不可放在下面。

 【规则 5.5】对变量的定义和分支语句,如果不是非常明显能看出

其意义,必须编写注释加以说明。

这些语句往往是程序实现某一特定功能的关键,对于维护人员来

说,良好的注释帮助更好的理解程序,有时甚至优于看设计文档。

【规则 5.6】对于 switch 语句下的 case 语句,如果因为特殊情况

需要处理完一个 case 后进入下一个 case 处理,必须在该 case 语句

处理完、下一个 case 语句前加上明确的注释。

这样比较清楚程序编写者的意图,有效防止无故遗漏 break 语句。

示例:

switch (input) {

    case 1: {}

    case 2: {

        prepareOneOrTwo();

        // fall through

    }

    case 3: {

        handleOneTwoOrThree();

        break;

    }

    default: {

        handleLargeNumber(input);

    }

}

 

【规则 5.7】边写代码边注释,修改代码同时修改相应的注释,以

保证注释与代码的一致性。不再有用的注释要删除。

【建议 5.1】免在一行代码或表达式的中间插入注释。

除非必要,不应在代码或表达中间插入注释,否则容易使代码可

理解性变差。

【建议 5.2】方法内的单行注释使用 //

【建议 5.3】一些复杂的代码需要说明。

示例:这里主要是对闰年算法的说明。

//1. 如果能被 4 整除,是闰年;

//2. 如果能被 100 整除,不是闰年.

 

//3. 如果能被 400 整除,是闰年.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

捐助开发者

在兴趣的驱动下,写一个免费的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(右上角的爱心标志,支持支付宝和PayPal捐助),没钱捧个人场,谢谢各位。



 
 
 谢谢您的赞助,我会做的更好!

 

 

 

 

 

 

展开阅读全文

没有更多推荐了,返回首页