编码规范 - 养成良好的Java编码习惯

最近在整理公司编码规范方面的内容,2017阿里巴巴发布了编码规范插件,强烈建议大家安装使用,好的编码习惯是通往成功的阶梯。

技术群二维码在底部,欢迎进群学习!!!

简书整套文档以及源码解析

专题 专题名称 专题描述
001 Spring Boot 核心技术 讲解SpringBoot一些企业级层面的核心组件
002 Spring Cloud 核心技术 对Spring Cloud核心技术全面讲解
003 QueryDSL 核心技术 全面讲解QueryDSL核心技术以及基于SpringBoot整合SpringDataJPA
004 SpringDataJPA 核心技术 全面讲解SpringDataJPA核心技术

文档目录

  • 注释规范
    • 类注释
    • 方法注释
    • 行级注释
    • DTO/Param注释
  • 编码规范
    • 命名风格
    • 常量定义
    • 代码格式
    • OOP 规约
    • 集合处理
    • 控制语句
  • 异常日志规范
    • 异常处理
    • 日志规约

一、注释规范

类注释

类、类属性使用Javadoc规范,类上描述该类的主要作用,注释尽可能详细,推荐把使用该类地方使用@see注解进行标注,类属性详细描述该属性的保存内容。
类注释示例

/**
 * 统一资源Aop切面定义
 * 根据自定义注解配置自动设置配置的资源类型到指定的字段
 * @author:于起宇 <br/>
 * ===============================
 * Created with IDEA.
 * Date:2017/12/15
 * Time:14:05
 * ================================
 */

类属性注释示例

/**
 * 资源处理业务逻辑
 */
Autowired
ResourcePushService resourcePushService;

方法注释

接口方法、实现类方法、抽象方法等,详细描述该方法主要作用,尽可能的描述出方法的主要流程步骤,方法定义的每一个参数都需要有详细的注释描述,建议添加方法返回值描述。
方法注释示例

    /**
     * 资源设置切面方法
     * 拦截配置了@ResourceMethod注解的class method
     * cglib仅支持class 方法切面,接口切面不支持
     * @param proceedingJoinPoint 切面方法实例
     * @param resourceMethod 方法注解实例
     * @return 原方法返回对象
     */
    @Around(value = "@annotation(resourceMethod)")
    public Object resourcePutAround(ProceedingJoinPoint proceedingJoinPoint, ResourceMethod resourceMethod)
        throws Throwable
    {
        //...
    }

如果是业务逻辑方法注释建议添加步骤,如下所示:

    /**
     * 创建帖子
     * - 转换参数实体为
     * - 保存帖子基本信息
     * @param param 创建帖子请求参数实体
     * @return 帖子编号
     * @throws LogicException
     */
    public String create(CreateTopicParam param) throws LogicException {
        //...
    }

在上面代码中-分隔符代表主要执行步骤,每一个步骤以-分隔符开始,如果方法内存在逻辑分支处理,请看下面行注释

行注释

行级注释一般都是方法内使用到,分为单行注释、多行注释,单行注释采用//设置,多行注释采用/* */设置,如下所示:
单行注释

// 执行方法,获取返回值

多行注释

/*
 * 执行方法,获取返回值
 * 获取返回值进行后续逻辑处理
 */

DTO/Param注释

我们在实际开发过程中数据库对应的实体是不允许直接拿出来添加一些附加字段的,也就是禁止添加非该数据表对应实体内的字段,这种情况我们需要定义DTO/Param

DTO注释

DTO是数据返回实体定义,如果我们在查询数据库时需要关联其他表的数据并且返回给前端,那么我们可以创建XxxDTO,注意:DTO全部大写,只需要继承查询逻辑的主表实体就可以完成附加字段的添加,要为每一个附加字段添加javadoc详细注释,如下所示:

/**
 * 帖子列表数据转换实体
 * @author:于起宇 <br/>
 * ===============================
 * Created with IDEA.
 * Date:2018/1/8
 * Time:10:52
 * ================================
 */
@Data
public class TopicListDTO
        extends CommunicationTopicInfoEntity {

    /**
     * 用户昵称
     */
    private String userNickName;
    /**
     * 所属机构名称
     */
    private String orgName;
    //...
}
Param注释

对于接口、后台来说接受请求时一般都是带着一些参数,目前我们系统是前台完全分离,所以后台其实变相的也是接口,在上面DTO也有说到数据实体不允许添加附加参数,我们的参数也不可能都是数据实体内的字段,这时需要创建对应的参数实体XxxParam,参数实体内的所有字段都需要添加javadoc注释,如下所示:

/**
 * 查询帖子列表
 * - 用于查询自己、他人、关键字、首页帖子请求参数
 *
 * @author:于起宇 <br/>
 * ===============================
 * Created with IDEA.
 * Date:2018/1/8
 * Time:10:31
 * ================================
 */
@Data
public class SelectTopicParam extends PagerParam {
    /**
     * 用户编号
     */
    private String userId;
    /**
     * 查询关键字
     */
    @Length(max = 30)
    private String keyWord;
}

二、编码规范

命名风格

  1. 代码中命名不能以下划线或美元符号开始,也不能以下划线或美元符合结束。

错误示例:

_name / name_ / $name / name$ / __name / name__
  1. 命名严禁出现中文拼音与英文混合方式出现,不允许直接使用中文方式命名

错误示例

WenZhang[文章] / WenZhangInfo[文章信息] / getTopicLieBiao()[获取文章列表] / int 数量 = 0
  1. 类名使用UpperCamelCase风格,DTOVO除外

错误示例

QRCode / UserInfoDto / XMLService

正确示例

QrCode / UserInfoDTO / XmlService
  1. 方法名、参数名、成员变量、局部变量统一使用lowerCamelCase风格,必须使用驼峰命名方式。

错误示例

localvalue / GetUserInfo() / userid

正确示例

localValue / getUserInfo() / userId
  1. 常量命名全部大写,单词间下划线隔开,完整的表达含义,名字可以过长。

错误示例

MAX_COUNT / NAME

正确示例

MAX_STOCK_COUNT / DEFAULT_ORG_NAME
  1. 抽象类命名使用Abstract或者Base开头,异常类命名使用Exception结尾,测试类命名时以将要测试的类全名 + Test

正确示例

AbstractCodeMessageService / BaseCodeMessageService / LogicException / UserControllerTest
  1. 包名统一使用小写,每个分隔符必须为自然语义的英文单词,另外包名统一使用单数含义,如果需要复数含义,则可以在类名上体现。

正确示例

com.sanmi.framework.core / com.sanmi.framework.orm
  1. 杜绝不规范的缩写,避免词义表达不清楚。

错误示例

AbstractClass = > AbsClass
condition => condi
  1. 接口中的方法和属性不要添加任何修饰符(public也不要添加),为了保持代码的简洁性,加上有效的javadoc注释。

错误示例

public abstract void commit();

正确示例

void commin(); / String COMPANY_NAME = "sanmi";
  1. 对于ServiceDAO类命名时实现类后缀要以Impl结尾,Mapper接口不存在实现类,无需处理。

正确示例

UserInfoService / UserInfoServiceImpl
  1. 枚举类名统一带上Enum后缀,枚举成员名称需要全大写,单词间使用下划线隔开。

正确示例

枚举名称 => UserStatusEnum
成员名称 => ENABLE / DISABLED / DELETE
  1. 各层方法命名规约
    Service/DAO/Mapper层方法命名规约如下:
    • 获取单个对象的方法用get作为前缀
    • 获取多个对象的方法用list作为前缀
    • 获取统计值的方法用count作为前缀
    • 插入方法用save / insert作为前缀
    • 删除方法用delete / remove作为前缀
    • 修改方法用update作为前缀

常量定义

  1. 不允许任何魔法值(未经过预先定义的常量)直接出现在代码中

错误示例

if("enable".equals(user.getStatus())) { 
   //.. 
}
  1. 使用封装类型代替基本数据类型

正确示例

Integer => int
Double => double
Long => long
...
  1. 如果常量仅在一个范围内变化,使用enum来代替定义

正确示例

@Getter
public enum  UserBzEnum
{
    /**
     * 普通用户
     */
    APP_USER("0"),
    /**
     * 月嫂
     */
    NANNY("1"),
    /**
     * 医生
     */
    DOCTOR("2")
    ;
    private String value;

    UserBzEnum(String value) {
        this.value = value;
    }
}

代码格式

  1. 大括号的使用约定,如果大括号内为空,直接使用{}即可,不需要换行;如果非空代码,则需要:
    • 左大括号前不换行
    • 左大括号后换行
    • 右大括号换行
    • 右大括号后还有else等代码则不换行;表示终止的右大括号后必须换行。
  2. 左小括号和字符之间不出现空格;右小括号和字符之间也不出现空格。
    错误示例
if ( a == b )
  1. if / for / while / switch / do 等保留字与括号之间都必须加空格
  2. 任何二目、三目运算符的左右两边都需要加一个空格。

正确示例

 if (ValidateTools.isEmpty(uploadBackEntity) || ValidateTools.isEmpty(uploadBackEntity.getUploadUrl())) {
 //...
        }
  1. 采用4个空格缩进,禁止使用Tab控制符。
  2. 行级注释的//与注释内容之间有且仅有一个空格。

正确示例

// 定义用户名
String userName = user.getName();
  1. 单行字符不超过120个,超过需要换行,换行原则如下:
    • 第二行相对于第一行缩进4哥空格,从第三行开始不再进行缩进
    • 运算符一起换行(如:+)
    • .符号一起换行
    • 方法调用中的多个参数需要换行时,在逗号后进行。

正确示例

StringBuffer buffer = new StringBuffer();
// 超过120个字符的情况下,换行缩进4个空格,``.``和方法名一块换行
buffer.append("san").append("mi") ...
        .append("ke")
        .append("ji");
// 参数过多超120个字符时,在 , 后换行
method(args1, args2, args3, ...
args98, args99
)        
  1. 方法参数在定义和传入时,多个参数后面必须加空格。
    正确示例
method(args1, args2);
OOP 规约
  1. 避免通过一个类的对象引用访问此类的静态变量或者静态方法,会造成编译器解析成本,直接用类名访问即可。【JVM堆、栈、静态代码块解析成本是不一样的】
  2. 所有覆盖方法,必须添加@Overrider注解
  3. 对外部正在调用或者二方库依赖的接口,不允许修改方法签名,以避免对接口调用方产生影响;如果接口已经过时,必须添加@Deprecated注解,并清晰的说明替代接口或者替代服务。
  4. 禁止使用过时类或方法。
  5. Objectequals方法容易抛出空指针异常,应使用常量或确定值的对象来调用equals方法。

错误示例

object.equals("test");

正确示例

"test".equals(object)
  1. 所有相同类型的封装类之间比较,必须使用equals方法。

说明int封装类Integer-128 ~ 127范围内的赋值会在IntegerCache.cache中产生,该区间的值可以直接使用==进行比对,但是该区间外的值都会以引用类型在内创建,对象之间是无法使用==来进行比对的!

  1. 构造函数内禁止编写任何业务逻辑,如果有业务逻辑请创建init方法使用。
集合处理
  1. 使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小则是list.size()

正确示例

List<String< list = new ArrayList();
list.add("jinan");
list.add("sanmi");
// 生成list长度的数组实例
String[] array = new String[list.size()];
// 执行集合转换数据
array = list.toArray(array);
  1. 在使用工具类Arrays.asList()方法时,不能使用修改集合相关的方法,add / remove / clean方法会抛出异常。
  2. 禁止在foreach循环内进行元素的remove / add操作,remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

正确示例

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    if (condition) {
        iterator.remove();
    }
}
控制语句
  1. 在一个switch内,每个case要么使用break / return来终止,要么注释说明程序将继续执行到具体的哪个case为止;在一个switch内必须包含default代码块在所有case之后,就算业务逻辑为空也要存在!
  2. if / else / for / while / do语句中必须使用大括号,即便是只有一行代码,也需要添加大括号。

错误示例

if (condition) statements;

正确示例

if (condition) {
    statements;
}
  1. 在表达异常分支时,尽可能的少用if / else if嵌套方式,可以修改成:
if (condition) {
    //...
    return object;
}
// 继续处理 else / else if 业务逻辑代码

如果不得不使用超过三层的if / else if逻辑判断,可以将代码改成卫语句策略设计模式状态设计模式,下面是卫语句示例:

public void today() {
    if (isBuy()) {
        System.out.println("do something.");
        return;
    }
    if (isFree()) {
        System.out.println("do something.");
        return;
    }
    System.out.println("coding..");
}

在我们系统设计时,一般都会使用throw new XxxException();return;代替,所有逻辑异常判断都采用自定义业务逻辑异常进行处理。

三、异常日志规范

异常规约
  1. Java 类库中定义的可以预判断来规避RuntimeException,不应该采用try {} catch(Exception e){}来处理。

错误示例

// 直接使用不确定对象
object.setXxx(value);

正确示例

// 判断非空后使用不确定对象
if (object != null) {
    //...
}
  1. 捕获异常目的是为了处理它,不要捕获了却什么都不处理而抛弃,如果不想处理它,请将该异常抛给它的调用者,最外层的业务使用者必须处理异常,将异常信息转换成用户可以理解的提示信息。
  2. try代码块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意rollback事务。
  3. finally代码块必须对资源对象、刘对象进行关闭操作,即使有异常也要做try-catch操作。
  4. 不能在finally代码块中使用return
  5. 业务逻辑异常请交付给框架处理,我们将业务逻辑验证使用业务逻辑异常处理的机制进行抛给框架处理。

正确示例

if (condition) {
    throw new LogicException(ErrorCodeEnum.USER_NOT_FOUND);
}
日志规约
  1. 代码中不可直接使用日志系统(Log4j、Logback)中的API,而依赖使用日志框架SLF4j中的API。使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
    正确示例
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// 获取日志对象
private static final Logger logger = LoggerFactory.getLogger(Xxx.class);

日志对象定义一般都会在项目框架搭建初期定义,直接使用即可,如果需要自定义,则按照上面的方式进行声明日志对象。

  1. trace / debug / info级别的日志输出,必须使用占位符的方式,如果不使用占位符而是直接拼接,可能会导致变量为null导致系统异常,还一点日志等级不匹配时虽然不会打印,但是会执行字符串的拼接,浪费服务器系统资源。

正确示例

logger.debug("执行查询用户:{},基本信息。",user.getId());
  1. 针对方法的主要参数需要打印对应的值,方便后期日志调试项目。

正确示例

public void today(String userId) {
    logger.debug("查询用户:{},今日任务完成进度",userId);
}
  1. 方法内分支逻辑需要打印对应的日志信息,方便后期日志调试项目。

正确示例

if (condition1) {
    logger.debug("do something.");
} else if (condition2) {
    logger.debug("do other thing.");
}
  1. 系统异常包括两大类:案发现场异常堆栈信息.

正确示例

logger.error(参数或对象.toString() + "_" + e.getMessage(), e);

写在最后

强烈建议IDEA开发工具安装使用阿里巴巴国际编码规约插件,为良好的编码习惯打下基础。

作者个人 博客
使用开源框架 ApiBoot 助你成为Api接口服务架构师

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容

  • 来源与:阿里云栖 禁止用于商业用途 ps:如果需要电子书 评论你们邮箱 我会发给你们 下面感觉还是有点乱 目录 一...
    小向资源网阅读 7,568评论 0 12
  • 目录 一、 编程规约..................................................
    owen_he阅读 4,905评论 0 4
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,573评论 18 139
  • 文/田螺菇凉77 原本是没打算去电影院看这部片名看起来有点中二,剧情狠虐超低泪点狗的电影。以为还是像白百合之前的《...
    田螺菇凉77阅读 408评论 2 4
  • 有时一个小小的动作,一句温暖的话,会改变一件事的进程。每时每刻以善心对待别人,你定会获得回报。 前一阵,教授安排几...
    Karren_3e9f阅读 272评论 0 0