Google Java编码风格


以下是摘自Hawstein的博客Google Java编程风格指南的学习笔记,下面仅列出我认为比较重要的知识点,没涉及到的可能是显而易见或约定俗成或者我觉得不重要的规范。使用良好的编码风格是coding最基本的素质之一。


1 源文件

1 源文件统一编码为UTF-8

2 特殊字符情形

a 除了行结束符外,空格是源文件唯一允许出现的空白字符,所有其他ASCII空白字符军需要进行转义,注意Tab符号一般表示制表符,不用于缩进。但是在很多编程场合下使用Tab的也大有人在。

我个人的认识是可能Tab在初次编写代码时确实比较好输入,而空格需要连续几次才行,但是后面如果有所更改或删除代码时(如多留空了),容易把Tab和空格弄糊涂,也可能与回退弄混,所以为了统一起见,默认可把Tab键设置成4或8个空格,Backspace键设置成2或4个空格,这样无论哪个键其实都是统一使用空格。Eclipse中貌似默认把Tab等价于8个空格,Backspace键设成4个空格。

b 对于具有特殊转义序列的任何字符(如\b),使用它的转义序列而不是它的Unicode转义; 对于一些非ASCII字符,使用实际的Unicode字符还是使用等价的Unicode转义字符如(\u221e),取决于对应代码的可读性。 不要害怕因为使用非ASCII字符而让你的代码可读性变差

3 源文件的组织结构

a 源文件按顺序的包括copyright或license(如有必要)、package语句、import语句、有且仅有一个顶级class,每个部分用一个空行隔开

b import语句规则

  • 不换行,不要使用通配符,即不要出现import java.util.*
  • import语句可按如下分组,顺序导入语句,且每组结束后用一个空行分隔,组内不空行,按字典序排列

顺序如下:

  1. 所有的静态导入成一组
  2. com.google导入(针对引用的源文件在此包下)
  3. 第三方的包(每个顶级包作为一组,按字典序,如com,junit,org)
  4. java导入
  5. javax导入

2 格式

1 在非空块和块状结构时(如类,方法的主体,条件语句或循环语句),要使用大括号,并且遵循K&R风格

int hello() { //左大括号之前不换行,之后换行
  //函数体中若是语句等的终止,右大括号后换行,否则不换行
   if (xxx) {
      //do something
   }
   
   if (xxx) {
         //do something
   } else {
     //do other thing
   }
} //右大括号前换行

2 应用水平空白的情形

  • 分隔任何保留字与紧随其后的左括号,如if,for,catch等(这个我平时用的不多)
  • 分隔任何保留字与其前面的右大括号,如else
  • 在任何大左括号前,除了@AnnotationXXX ({a,b})等不使用空格
  • 在任何二元或三元运算符两侧都要使用空格,也适用于类运算符,如<T extends Foo & Bar>
  • , : ; )后都应添加空格
  • 不建议让注释水平对齐,修改内容后就使得对齐代码错位,不方便维护,所以建议一开始就无需对齐

**3 每次只声明一个变量,不要使用组合声明int a,b **

4 数组初始化可写成块状结构

new int[] {
 0, 1, 2, 3
}

new int[] {
 0, 1
 2, 3
}

5 在switch语句中如果程序将继续执行到下一个语句组,需要添加能够表达该意思的注释,该特殊的注释无需在最后default:中出现并且默认情况必须要写出来,即使什么代码不包括

switch (intput) {
        case 1:
        case 2:
                xxx;
                //fall through
        case 3:
                xxx;
                break;
        default:
                xxx;
}

6 注解独占一行,用于类,方法构造函数中

@Override
@Nullable
public String get() {
        ...
}
//只要是合法的,重写@Override的注解能用则用

//例外: 单个注解可和函数签名第一行出现在同一行中
@Override public int hashCode() {
        ...
}

//用于字段的注解随文档块出现,也可允许出现在同一行
@XXX @YYY DataLoader loader;

7 注释风格,建议统一使用Javadoc方式

/**
 * 用于描述方法或类
 */
 
/** 单行形式,一般用于描述类的变量 */

// 用于描述方法内部的单个语句

Javadoc有一些约定俗称的标记,例如

  • 除首段落,每个段落第一个单词前都有标签<p>,并且它和第一个单词没有空格
  • Javadoc标记按如下顺序出现: @param,@return,@throws,@deprecated,且描述都不能为空
  • 一个单行的简要片段,应该写成/** get xxx*/,而不是/** @return xxx*/

例如JDK库中的StringBuilder类描述

/**
 * A mutable sequence of characters.  This class provides an API compatible
 * with <code>StringBuffer</code>, but with no guarantee of synchronization.
 * This class is designed for use as a drop-in replacement for
 * <code>StringBuffer</code> in places where the string buffer was being
 * used by a single thread (as is generally the case).   Where possible,
 * it is recommended that this class be used in preference to
 * <code>StringBuffer</code> as it will be faster under most implementations.
 *
 * <p>
 * For example, if <code>z</code> refers to a string builder object
 * whose current contents are "<code>start</code>", then
 * the method call <code>z.append("le")</code> would cause the string
 * builder to contain "<code>startle</code>", whereas
 * <code>z.insert(4, "le")</code> would alter the string builder to
 * contain "<code>starlet</code>".
 *
 * @author      Michael McCloskey
 * @see         java.lang.StringBuffer
 * @see         java.lang.String
 * @since       1.5
 */
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /** use serialVersionUID for interoperability */
    static final long serialVersionUID = 4383685877147921099L;

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuilder() {
        super(16);
    }

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity specified by the <code>capacity</code> argument.
     *
     * @param      capacity  the initial capacity.
     * @throws     NegativeArraySizeException  if the <code>capacity</code>
     *               argument is less than <code>0</code>.
     */
    public StringBuilder(int capacity) {
        super(capacity);
    }

8 捕获的异常不能忽视,必须响应。如果catch块确实不需要回应,必须要加注释以说明;另外如果能确保测试的方法会抛出一个期望的异常,就没必要加注释

try {
        xxx;
        fail();
} catch (NoSuchElementException expected) {
}

3 命名

标识符只能使用ASCII字母和数字,即每个有效的标识符名称都匹配正则表达式\W+。注意在Google其他编程语言风格中使用的特殊前缀,如mName,s_name,name_等均不能在Java中使用。

驼峰式命名法分为UpperCamelCase和lowerCamerCase。这个英文写法就说明了命名的规则,按单词划分根据命名规则决定每个单词首字母的大小写,再连接起来形成一个标识符

1 如果类和成员的修饰符都存在,按Java语言规范推荐的顺序出现

public protected private abstract static final transient volatile synchronized
native strictfp

2 包名全部小写,连续的单词直接连接起来,且不使用下划线

3 常量命名模式为CONSTANT_CASE,全部字母大写,用下划线分割单词

每个常量都是一个静态final字段但并非所有这样的字段都是常量。决定是否常量是取决于它的实际情况,如果永远不打算改变对象,一直不变则设为常量。如下面例子

//Constants
static final int NUMBER = 5;
static final Joiner COMMA_JOINER = Joiner.on(','); //immutable Joiner
static final Immutable<String> NAMES = ImmutableList.of("Ed", "Ann");
enum SomeEnum { ENUM_CONS }
static final SomeType[] EMPTY_ARRAY = []; //不变类

//Not constants
static String nonfinal = "non-final";
final String nonstatic = "non-static";
static final Set<String> mutableCollection = new HashSet<String>();
static final String[] nonEmptyArray = {"these", "can", "change"};
static final ImmutableSet<XXX> mutableElements = ImmutableSet.of(mutable);
static final Logger logger = Logger.getLogger(MyClass.getName());

4 类名统一使用UpperCamelCase风格编写,通常是名词或名词短语,接口有可能是形容词或形容词短语。测试类命令以它要测试的类名称开始,以Test结束

5 方法名、非常量字段名、参数名和局部变量名都是lowerCamelCase风格。方法名要求是动词或动词短语,参数和局部变量名尽量避免使用单字符命名,除了循环变量和临时变量


参考

  1. Google Java Style
  2. Google Java编程风格指南