编码规范

官方商城编码规范
版本:1.0

目的
本规范的目的是通过建立编码规范统一每个开发人员的编码习惯,提高程序的可靠性、可读性、可修改性、可维护性及一致性,增加团队合作开发效率,为各项目组之间或项目组内成员之间的技术交流提供一个方便统一的方式。
范围
本规范适用于公司内所有运用JAVA技术的软件项目、产品等的设计、开发以及维护、升级等。
本规范适用于公司所有JAVA软件开发人员。
本规范建议的开发环境与工具如下:
IDE: IntelliJ IDEA 2018.3.5 以上版本
插件: Maven 3.0以上版本,
JDK: Sun JDK 1.8以上版本

基本Java编码规范
基本规范

编码中的命名必须有意义且易于理解。常量名全部大写,用“_”分隔单词,变量名开始小写,之后的单词首字母大写。

public static final String MANUFACTURE_CODE = “MANUFACTURE_CODE”;

不允许任何魔法值 ( 即未经定义的常量 ) 直接出现在代码中
long 或者 Long 初始赋值时,使用大写的 L ,不能是小写的 l ,小写容易跟数字 1 混

淆,造成误解
Long categoryId = 1L; //L使用大写以避免和1混淆

保持正确的缩进匹配。建议在代码编写完毕后使用Idea的格式化代码功能格式化代码。
移除所有无用的编码和注释
保证必要的注释以用于描述代码逻辑和流程,更加具体的要求见注释说明部分
使用常量定义避免系统中出现的硬编码,与实体相关的常量定义在实体类中,系统公共常量定义在Constants类中
对于所有实体,都需实现java.io.Serializable接口。同时对于实现该接口的对象,都需要使用Idea的功能生成对应的序列号,如:

private static final long serialVersionUID = 3616593248717989335L;

在使用equals方法和常量进行比较时,需要将常量写在前面以防止NullpointerException的出现,如

public static final String STATUS_ENABLE = “ENABLE”;
public boolean isEnable(Part p){
return STATUS_ENABLE.equals(p.getStatus());
}

尽量避免出现使用“+”进行的大量的字符串连接操作,如果一定需要动态连接字符串,使用StringBuffer或者StringBuilder类
字符串操作前必须非空校验
字符串替换推荐使用replace 代替replaceAll
页面或其他系统传递的字符串trim()处理
禁止在代码中使用System.out.println();
集合初始化时,推荐指定集合初始值大小。
Java 7引入了菱形算子(<>)来减少泛型代码的冗长性,如:

Map<String,Object> map = new HashMap<String, Object>();//错误
Map<String,Object> map = new HashMap<();//正确

不要在 foreach 循环里进行元素的 remove / add 操作。 remove 元素请使用 Iterator

方式,如果并发操作,需要对 Iterator 对象加锁。

避免在controller层写业务代码
代码应符合单一职责原则
对于定义为包装类的字段,如果需要默认值,请设置默认值,避难出现不期望的业务异常。
包装类比较使用equal,不能用==
代码逻辑清晰,必要业务添加注释,if,for循环判断语句保证在3层以内。
推荐使用spring的copy方法,不推荐使用Apache。BeanUtils.copyProperties
推荐使用国际化
线程资源必须通过线程池提供,不允许在应用中自行显式创建线程
线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式

为了编码的一致性,统一将编码方式设置为UTF-8编码

代码格式规范
换行

每行代码的长度不要超过255个字符(推荐在150字符以内)
当代码过长,无法在一行内显示时,请按以下规则进行换行: 在逗号、点号或者等号后换行 在操作符前换行 新换行前保持一定的缩进以对齐代码或者便于阅读

间隔

类、方法及功能块间等应以空行相隔,以增加可读性,但不得有无规则的大片空行。操作符两端应当各空一个字符以增加可读性。相应独立的功能模块之间可使用注释行间隔,并标明相应内容。

对齐

关系密切的行应对齐,对齐包括类型、修饰、名称、参数等各部分对齐。连续赋值时应当对齐操作符。当方法参数过多时在适当的参数后(逗号后)换行并对齐。当控制或循环中的条件比较长时当换行(操作符前)、对齐并注释各条件。

日志规范

系统使用日志跟踪编码业务,日志使用slf4j,如果当前类的基类中不含日志对象的定义,则按如下格式添加:

protected static final Logger logger = LoggerFactory.getLogger(BaseAction.class);

使用DEBUG级别打印必要的调试信息用于测试
使用INFO级别输出一些关键事件
使用WARN级别输出一些警告事件,这些事件不会导致系统问题,但可能是用户在操作时遗漏某些内容。如某参数未配置,系统自动使用默认参数等
使用ERROR级别在catch块中输出异常信息
如果进行了抛出异常操作,请不要记录error日志,由最终处理方进行处理

对 trace / debug / info 级别的日志输出,必须使用条件输出形式或者使用占位符的方

式。

条件
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}
占位符
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

命名规范
规范的命名能使程序更易阅读,从而更易于理解。它们也可以提供一些标识功能方面的信息,有助于更好的理解代码和应用。
基本约定

使用可以准确说明变量/字段/类/接口/包等的完整的英文描述符。例如,采用类似firstName,listAllUsers 或CorporateCustomer 这样的名字,严禁使用汉语拼音及不相关单词命名,虽然Java 支持Unicode 命名,但本规范规定对包、类、接口、方法、变量、字段等不得使用汉字等进行命名。
采用该领域的术语。如果用户称他们的“客户”(clients) 为“顾客”(customers),那么就采用术语Customer 来命名这个类,而不用Client。
采用大小写混合,提高名字的可读性。一般应该采用小写字母,但是类和接口的名字的首字母,以及任何中间单词的首字母应该大写。包名全部小写。
尽量少用缩写,但如果一定要使用,当使用公共缩写和习惯缩写等,如实现(implement)可缩写成impl,应用程序(application)可缩写成app 等,严禁滥用缩写。
避免使用长名字(最好不超过25 个字母)。
避免使用相似或者仅在大小写上有区别的名字。
避免使用数字,但可用2 代替to,用4 代替for 等,如:go2Jsp。
遇到缩写如XML 时, 仅首字母大写, 即loadXmlDocument() 而不是loadXMLDocument()。

文件、包

文件名当与其类严格相同,所有单词首字母大写。
包名一般以项目或模块名命名,少用缩写和长名,一律小写。
基本包:com.charleskeith.microservice,所有包、文件都从属于此包。
包名按规则组成:[基本包] . [项目名] . [模块名] . [子模块名]…
不得将类直接定义在基本包下,所有项目中的类、接口等都当定义在各自的项目和模块包中。

类、接口
所有单词首字母大写。使用能确切反应该类、接口含义、功能等的词。一般采用名词。接口可以可以在名词后加大写Impl,如QsLimitedManagerImpl。

传递给页面的请求实体 ,以request结尾 ,例如:LoginRequest
页面响应后返回的实体 ,以response结尾 ,例如:LoginResponse
与其他系统交互需要对外提供的实体,以VO, 例如:LoginVO
DAO的命名使用<实体名>Repository,存放在repository包中。
业务逻辑类的命名使用<业务逻辑分类名>Service,存放在service包中。
控制类的命名使用<实体或者具体操作场景>Controller,存放在controller包中。
枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。

字段

业采用完整的英文大写单词,在词与词之间用下划线连接,如:DEFAULT_VALUE
对不易清楚识别出该变量类型的变量应使用类型缩写作其前缀,如字符串使用strXXX,boolean 使用isXXX,hasXXX 等等。除第一各个单词外其余单词首字母大写。对私有实例变量可使用下划线“_”前缀,但在其存取方法中则应该将其前缀去掉。局部变量及输入参数不要与类成员变量同名(get/set 方法与构造函数除外)。
实体中的只读属性需要有Transient标签标识以避免在数据库中增加冗余字段,如

@Transient
public BigDecimal getTotalforOrder()

实体类字段需添加必要的注释解释说明其含义

方法

使用 create[List][Suffix] 来定义一个数据模型的创建方法,推荐返回值为创建后的数据对象
使用 update[List][Suffix] 来定义一个数据模型的更新方法,推荐返回值为更新后的数据对象
使用 createOrUpdate[List][Suffix] 来定义一个数据模型的创建/更新方法,推荐返回值为新创建/修改的数据对象
使用 delete[List][Suffix] 来定义删除方法,推荐返回值为null或删除的记录数
使用 find[List][Suffix][Sql] 来定义查询方法,如果是DAO中的方法,且使用了SQL查询,则需要加Sql后缀
对于定义的接口,实现类的类名默认为接口名 + Impl

注: 是指操作相关的Entity或者Command名称,如Sku,SalesOrderCommand [List] 是指当方法影响/相关的的实体是一组而不是一个时,方法名中加上List [Suffix] 是指方法的额外说明,如 ByCode 等

注释规范
基本原则
注释应该增加代码的清晰度。代码注释的目的是要使代码更易于被其他开发人员等理解。注释信息不仅要包括代码的功能,还应给出原因。除变量定义等较短语句的注释可用行尾注释外,其他注释当避免使用行尾注释。
文件注释
在每个文件、包的头部都应该包含该文件的功能、作用、作者、版权以及创建、修改记录等。并在其中使用版本仓库标记自动跟踪版本变化及修改记录等信息。注意是标准的C-Style// 注释而不是/* …*/ 形式的JavaDoc 注释。
Java Doc 注释
对类、方法、变量等的注释需要符合JavaDoc 规范,对每个类、方法都应详细说明其功能、条件、参数等,并使用良好的HTML 标记格式化注释,以使生成的JavaDoc易阅读和理解。
类注释中当包含版本和作者信息,使用版本仓库的标记自动跟踪版本变化和修改记
录,如下。
/**

  • 用于示例的类
  • @author test
  • @version R e v Rev Rev

    */
    public class Test {
    private static final Logger logger = Logger.getLogger(Test.class);

/**
*一个测试的方法
*@param userid 用户编号
@return 返回用户信息对象,若无该用户信息,则返回null
/
private UserInfo getStrings(Integer userid) {
……………
return userInfo;
}
}
失效代码注释
由/
/界定,标准的C-Style 的注释。专用于注释已失效的代码。
/username = “”;
password = “”;
currentCar = “”;
logined = false;
attributes = new HashMap();
attributes.put(“title”, “hello”);
/
失效注释快捷键是Ctrl+Shift+/ ,取消注释是Ctrl+Shift+
代码细节注释
由// 界定,专用于注释代码细节,即使有多行注释也仍然使用//,以便与用/**/注
释的失效代码分开除了私有变量外,不推荐使用行末注释。
//设置CarBean
for(int i=0; i < 20; i++)
{
//首先需要生成实例
CarBean bean = new CarBean();
bean.setBaseprice(11);
bean.setDescription(“aa”);
bean.setName(“1111”);
cdao.save(bean);
}
注释的格式

注释中的第一个句子要以(英文)句号、问号或者感叹号结束。Javadoc 生成工具会将注释中的第一个句子放在方法汇总表和索引中。
为了在JavaDoc 和IDE 中能快速链接跳转到相关联的类与方法,尽量多的使用@see xxx.MyClass,@see xx.MyClass#find(String)。
Class 必须以@author 作者名声明作者,不需要声明手工指定@version 与@date,由版本管理系统保留此信息。
如果注释中有超过一个段落,用

分隔。
示例代码以

包裹。 

标识(java keyword, class/method/field/argument 名,Constants) 以 包裹。

标识在第一次出现时以{@linkxxx.Myclass}注解以便JavaDoc 与IDE 中可以链接。
注释的内容

对于API 函数如果存在契约,必须写明它的前置条件(precondition),后置条件(postcondition),及不变式(invariant)。
对于调用复杂的API 尽量提供代码示例。
对于已知的Bug 需要声明。
在本函数中抛出的unchecked exception 尽量用@throws 说明。
注释中的每一个单词都要有其不可缺少的意义,注释里不写"@param name -名字"无意义的内容。
注释的标签必须有内容,不能存在空的@param name,空的@return。

错误与异常规范
基本原则
 通常的思想是只对错误采用异常处理:逻辑和编程错误,设置错误,被破坏的数据,资源耗尽,等等。通常的法则是系统在正常状态下以及无重载和硬件失效状态下,不应产生任何异常。最小化从一个给定的抽象类中导出的异常的个数。对于经常发生的可预计事件不要采用异常。不要使用异常实现控制结构。确保状态码有一个正确值。在本地进行安全性检查,而不是让用户去做。若有finally 子句,则不要在try 块中直接返回,亦不要在finally 中直接返回。

已检查异常与运行时异常
 已检查异常必须捕捉并做相应处理,不能将已检查异常抛到系统之外去处理。对可预见的运行时异常当进行捕捉并处理,比如空指针等。通常,对空指针的判断不是使用捕捉NullPointException 的方式,而是在调用该对象之前使用判断语句进行直接判断。建议使用运行时异常(RuntimeException)代替已检查异常(CheckedException)。

异常处理
 重新抛出的异常必须保留原来的异常,即throw new NewException(“message”,e); 而不能写成throw new NewException(“message”)。在所有异常被捕获且没有重新抛出的地方必须写日志,避免异常的湮没。如果属于正常异常的空异常处理块必须注释说明原因,否则不允许空的catch块。框架尽量捕获低级异常,并封装成高级异常重新抛出,隐藏低级异常的细节。多个异常应分别捕捉并处理,避免使用一个单一的catch 来处理。

不能在 finally 块中使用 return , finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句
Java 类库中定义的一类 RuntimeException 可以通过预先检查进行规避,而不应该

通过 catch 来处理,比如: IndexOutOfBoundsException , NullPointerException 等等

异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws 往上抛出,Web 层绝不应该继续往上抛异常,因为已处于顶层。
finally 块必须对资源对象、流对象进行关闭,有异常也要做 try - catch
异常日志统一用log日志规范输出,避免使用e.printStackTrace()
Try-Catch块不应嵌套

其他

基本消除项目中所有的警告项,主要含以下几方面:

对于所有实现java.io.Serializable接口的对象生成对应的序列号
对于强制类型转换,使用 @SuppressWarning(“unchecked”) 消除警告
对于未使用的变量或方法,如需保留,使用 @SuppressWarning(“unused”) 消除警告,否则删除
对于使用已经Deprecate的方法的方法,如无替代方案使用,使用 @SuppressWarning(“deprecated”) 消除警告,否则使用替代方案

修改代码后,删除不必要的 @SuppressWarning 注释。
对于计划需完成但尚未完成的编码块,或自顶向下实现业务逻辑时尚未实现的逻辑部分,使用//TODO 添加待处理项以确保不会遗漏。

业务逻辑规范

业务逻辑类都交由Spring管理,作为ApplicationContext中的一个单态bean存在。
使用标准注解@Service定义业务逻辑类,需显示定义Bean的名称。
如有需求,使用@Resource注入ApplicationContext。
使用标准注解@PostConstruct定义业务逻辑类初始化后的后续操作
使用@Autowired定义注入和依赖关系

所有需要切入事务控制的类都使用@Transactional注释实现事务的切入。回滚异常使用默认设置:所有的RuntimeException会导致事务的回滚
推荐基于业务类的级别定义事务注入,即一个业务类要么没有事务,要么所有方法都注入事务,不存在部分方法注入事务,部分不注入的情况。因此,对于类上未定义@Transactional的业务逻辑类,不推荐在方法上注入事务。事务注入都在实现类上操作,不在接口上操作。
所有仅用于查询显示数据的方法,都将事务定义为只读事务@Transactional(readOnly=true)

集合
避免使用Vector 和HashTable 等旧的集合实现,这些实现的存在仅是为了与旧的系统兼容,而且由于这些实现是同步的,故而在大量操作时会带来不必要的性能损失。在新的系统设计中不当出现这些实现,使用ArrayList 代替Vector,使用HashMap 代替HashTable。
若却是需要使用同步集合类,当使用如下方式获得同步集合实例:
Map map = Collections.synchronizedMap(new HashMap());
由于数组、ArrayList 与Vector 之间的性能差异巨大(具体参见《Java fitball》),故在能使用数组时不要使用ArrayList,尽量避免使用Vector。

同步
 尽量少用同步方法,避免使用太多的synchronized 关键字。
 尽量将同步最小化,即将同步作用到最需要的地方,避免大块的同步块或方法
等。
SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为
static ,必须加锁,或者使用 DateUtils 工具类。

ArrayList or LinkedList instead of Vector
Deque instead of Stack
HashMap instead of Hashtable
StringBuilder instead of StringBuffer

–文档结束–

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值