Java源文件规约

Leon讨论 | 贡献2019年7月18日 (四) 12:28的版本 前言

前言

本文档是研发规范的一部分,阐述一般性Java源文件的结构规范。

本文档关注一般源代码文件的组成项目、项目之间先后顺序的规定,以及格式要求。

本文档没有阐明各个项目元素的命名规范,这部分请参考:《平台代码规约》。

阅读本文档前请先阅读《阿里巴巴Java开发手册.pdf》,与本规约冲突的地方以本规约为准

结构规定

结构概览

  • 文件头声明
  • package行
  • import块
  • 类声明
  • 静态成员变量 / Static Fields
  • 静态初始化块 / Static Initialize
  • public静态方法 / Public Static Methods
  • 成员变量 / Fields
  • 初始化块 / Initializer
  • 构造器 / Constructors
  • 成员方法 / Methods
  • 非静态成员方法 / Static Methods
  • 重载自Object的方法如toString(), hashCode() 和main方法
  • 类型(内部类) / Types(Inner Classes)

同等的类型,按private, protected, public的顺序排列。

文件头声明

文件头注释需标明SVN版本替换标签与版权信息两部分内容,如:

/**
 * $Id:$
 * Copyright 2014-2017 Hebei Sinounited Technology Company Ltd. All rights reserved.
 */
package com.opensource.ap.security.service;

在源码提交SVN服务器后,SVN版本替换标签信息将自动替换为文件名称、版本号、提交版本服务器时间、提交用户名等内容,如:

/**
 * $Id: ApOrganService.java 210 2017-02-16 11:28:18Z Jades_He $
 * Copyright 2014-2017 Hebei Sinounited Technology Company Ltd. All rights reserved.
 */
package com.opensource.ap.security.service;

package行

package声明紧跟在文件头声明内容之后、Import块之前,与其后内容留一空行,如:

/**
 * $Id: ApOrganService.java 211 2015-05-25 11:33:24Z Jades_He $
 * Copyright 2014-2015 Hebei Sinounited Technology Company Ltd. All rights reserved.
 */
package com.opensource.ap.security.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import块

import块在package行之后、类声明之前,与前后内容之间各留一空行。

静态导入(import static)在前,类导入在后。

静态导入内容必须精确到变量或方法、导入类必须精确到具体的类。

不同导入部分之间留一空行。

可使用Eclipse快捷方式ctrl + shirt + o自动完成。

/**
 * $Id: ApOrganService.java 212 2015-05-25 11:39:47Z Jades_He $
 * Copyright 2014-2015 Hebei Sinounited Technology Company Ltd. All rights reserved.
 */
package com.opensource.ap.security.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.opensource.ap.entity.ApOrganEntity;
import com.opensource.ap.security.constant.SecurityConstant;

类声明

包括类Java Doc注释和类声明行两部分,注释在前,声明在后。

类注释在import块之后,与其之间有一空行类注释需填写类摘要说明、@author、@since等必选信息,根据需要填写@version等信息。

作为API提供的类,应在注释中简单说明如何使用,以及其它有助于快速、正确使用它的有关信息。

类注释后紧跟类声明,其间无空行,如:

/**
 * 依照研发部《Java源文件规范》进行创建,用于提供一个示例。
 * 
 * <p>
 * 在《Java源文件规范》中将使用到这个源文件的代码片段,形象说明规范要点。
 * </p>
 * 
 * <p>
 * 如果注释中出现和HTML冲突的字符,比如大于号{@literal >},小于号{@literal <},请使用@literal处理。
 * </p>
 * 
 * @author Jades.He
 * @since 2015年5月25日 下午8:11:59
 */
public class JavaSourceDemo {

静态成员变量&静态初始化块

final域在前,非final域变量在后

private在前,public在后。

域的初始化块紧接在域声明后,分开使用初始化块,不合成一起。

综合初始化块,在所有域和静态初始化块后:

public class JavaSourceDemo implements Serializable {

 /** serialVersionUID */
 private static final long serialVersionUID = 1L;

 /** Logger */
 protected static final Logger logger = LoggerFactory.getLogger(JavaSourceDemo.class);

 /** 静态常量 */
 public static String VERSION;

 static {
  VERSION = "1.0.0";
 }

public静态方法

public静态方法在成员变量和构造器之前。

main方法在所有静态方法之前。

main方法要对输入参数格式做注释说明。

成员变量&实例初始化块

成员变量应定义为private或protected,谨慎使用public。

成员变量应提供简单的/** */单行注释,标明其中文名称或职责功能。

成员变量与成员变量之间空一行。

 /** 用户名 */
 private String username;

 /** 密码 */
 private String password = "123";

构造器

构造器在实例成员后,实例方法前;

根据Java语言规范,当类没有声明任何构造器时,Java认为其默认具有一个无参构造器;

当类明确声明了构造器,Java不再为类默认添加任何构造器;

有多个构造器时,参数少的在前,多的在后。 构造器的注释应该注重说明意图以及参数对对象的影响; 构造器的个数应该控制在有限个数内,否则应该使用Builder模式、静态工厂方法模式等替代方案(请参见<Effective Java>);

实例方法顺序

一般原则:

getter/setter方法,:getter在前,setter在后,使用eclipse自动生成Java Doc注释即可。

  • private方法
  • protected方法
  • package-protected方法
  • public方法

对一组功能类似的方法,short-cut的方法在前,复杂的方法在后。

常用方法排序示例:

  • page 方法
  • list 方法
  • get 方法
  • insert 方法
  • update 方法
  • delete 方法


实例方法的声明

对abstract方法实现的,重写父类方法的,必须声明@Override;

对有相同参数个数的重载方法(overloaded)或称多态方法的,应该非常谨慎,改个名字最好;

对public、protected一定要写Java Doc注释,而且是有效的。

非public静态方法

原则上:所有非public静态方法应该在所有实例方法之后,具名内部类前

这类静态方法往往是一些函数性、工具性的方法

特例:有些非public静态方法,是为一组功能相似或紧密的方法使用的,如果放在这些静态或实例方法后面更有助于代码阅读,应贯彻此特例。这类同于short-cut

请参考String.javaindexOflastIndexOf两个静态方法的位置。

注释规定

对public和protected的元素都必须写Java Doc注释:说明API意图/功能(第一行)、是否可用于多线程(默认不说明应该保证可用于多线程下)、是否是线程安全的(默认不说明应该保证线程安全) 、输入参数规格(@param)、输出规格(@return)、对象或参数处于某特定状态将抛什么异常(@throws),以及对使用该类或方法的前提条件以及后置条件进行说明(如有限制的话)

Java Doc注释不要过多陈述“代码的内部实现”,而应从使用者的角度进行陈述。

对public/protected元素而言,Java Doc说明甚至是最重要的资产。

对private方法,也应该简单说明一下其意图或功能,以便于后续维护。

类注释

类声明

方法注释

方法注释需填写摘要说明、@author、@since等必选信息。

  /**
   * 
   * @param args
   * @author Jades.He
   * @since 2017年2月17日 上午9:10:12
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub
  }

失效代码注释

/*...*/界定,标准的C-Style的注释。专用于注释已失效的代码。

/*
 * Comment out the code
 * String s = "hello";
 * System.out.println(s);
 */

代码细节注释

由//界定,专用于注释代码细节,即使有多行注释也仍然使用//,以便与用/**/注释的失效代码分开 除了私有变量外,不推荐使用行末注释。其他代码使用行首注释

class MyClass {
    /** An end-line comment. */
    private int myField;
    public void myMethod {
       // a very very long
       // comment.
       if (condition1) {
          // condition1 comment
          ...
        } else {
          // elses condition comment
          ...
        }
    }
}

其他规定

代码字符规定

源代码使用UTF-8进行编码,创建Java工程时应进行确认或调整。

请把Eclpse的默认环境设置为UTF-8 Eclipse -> General -> Workspace -> Text file encoding -> Other UTF-8

例外:properities文件请默认保持拉丁字符集,不可调为UTF-8或GBK

源代码换行符,明确调整为Unix方式

我们的开发人员普遍使用Window和Unix操作系统开发,为统一起见而规此定。

Eclipse -> General -> Workspace -> New Text file line delimiter -> Other Unix

代码长宽限制

Java方法代码长度避免超过120行(不含方法头的Java Doc注释)

Java源文件宽度禁止超过120英文字符的宽度 (请通过Eclipse等IDE进行设置控制,请注意中文字符的宽度大于英文字符,所以应使用Eclipse控制注释的宽度在100个以内)

每个Java代码行(不管是否折行了),在调用方可调整的情况下,禁止超过120个字符

违反以上规定,不仅仅妨碍了代码可读性的提高,往往也意味中代码在设计、开发上有相当的改进空间。应寻找时间改善,提升代码设计质量、可维护性。

代码折行策略

在分隔符号后折行

逗号(,) 分号(;) 赋值号(=)

Eclipse格式化可以自动调整,使符合此规范。

在运算符号前折行

算术符号(+, -, *),关系运算符(&&, ||), ...

Eclipse格式化可以自动调整,使符合此规范。

考虑使用行注释符//

IDE的折行策略大部分是可行的,但是也有一些折行,IDE工具处理得很糟糕。

通过行注释符可以强制改变IDE自动折行策略,使按照我们定义的方式折行。

可在 // 后,写 NL (=new line),以明确告知读者,这里用于折行

   MemberDealerAcct memberDealerAcct = memberDealerAcctDao.selectByPrimaryKey( // NL
     memberFeeDtl.getMemberDealerAcctId());

代码缩进策略

使用空格缩进,宽度默认为2个字符

Eclipse格式化可以自动调整,使符合此规范。

Annotation标注风格

请使用 不使用
@Override
 public String toString() {
     return xxx;
 }

// 如果有多个Annotation,每个一行
@Override public String toString() {
     return xxx;
 }

public @Override String toString() {
     return xxx;
 }

泛型使用规定

按照《Effective Java》建议,在新代码中应该使用泛型;

对List,Set, Map等集合类,我们强制使用;

对兼容旧代码的,实在没办法处理的,必须使用@SuppressWarnings("uncheck")处理,但禁止在Class级别使用,只能使用在方法或变量级别;

提交到版本库的代码不能出现warnnings警告

方法的命名规则

方法命名的基本原则:见名知意 一般的方法名采用两个单词动宾结构形式的名称,两个单词之间不要带其它符号,第二个单词的首字母大写,其它的都小写。 如:findUser(int userId)、deleteUser(int userId) 只有一个动词形式的方法名不推荐使用。 不容易看明白的方法名或有歧义的方法名可采用多单词的形式,每两个单词之间不要带其它符号,从第二个单词开始,每个单词的首字母大写,其它的都小写如:findUserByUserId(int userId)、findUserByUserIdAndYear(int userId, int year)

odds & ends

  • 一行文本行,不要有2个代码行:argv++; argc--; // AVOID!
  • 对单独的if-else里面的语句,强制使用括号
  • 覆盖或实现父类的方法必须标明注解:@Override
  • 判断一个对象不为空时不使用 !=null来判断,应使用如下方式:
    if (!(entity == null)) {
      // TODO
    }
  • 代码中的TODO必须有实际意义,IDE自动生成的需删除:
  public static void main(String[] args) {
    // 下一行自动生成的TODO必须删除!
    // TODO Auto-generated method stub
  }