Oracle规范笔记
摘自:https://www.oracle.com/technetwork/java/codeconvtoc-136057.html
1. 介绍
1.1为什么要规范
- 80%的时间用于软件的维护
- 任何软件很难一直被原始作者维护
- 代码规范提升程序的可读性,让工程师可以更快、更全面的理解代码
- 如果要将源码作为产品推向市场,需要确保它像其他的产品一样包装玩好且代码整洁
2.文件名
2.1文件后缀
源码文件(Java source)->.java
字节码文件(Java bytecode)->.class
2.2 一些通用的文件
File Name Use
GNUmakefile 构建软件(不是很了解,后期需要学习)
README 总结特定目录的文件名
3.文件组织
一个文件由很多节组成,节与节之间用一些空行和一个能够区分每个节的注释分割(注释可有可无)。
行数超过2000的文件是冗长的,不易操作。
例子请见下面的“源文件举例”。
3.1Java源文件
每一个java源文件含有一个public类或者是接口。当private类和接口与public类相关时,可以把它们放在public类所在源文件。public类必须是文件中第一个类或接口。
java源文件有以下要求:
- 起始注释(后面介绍)
- Package和Import语句
- 类与接口的声明
3.1.1起始注释
所有的源文件能够以c注释格式开始,c-style含有类名,版本信息、数据和版权布告:
/*
*Classname
*
*Version information
*
*Date
*
*Copyright
*/
3.1.2Package和Import语句
第一行非注释代码是package语句。紧接着是import语句,举例:
package java.awt;
import java.awt.peer.CanvasPeer;
3.1.3类和接口的声明
- 类和接口的文件注释 /**…*/
- 类和接口的实现注释 /**…*/
4.缩进
四个空格作为缩进的一个单元。具体的缩进结构不确定。Tabs必须与8个空格等同。
4.1行的长度
避免一行的字符超过80个,因为这样不能够很好地被许多终端和工具处理。
**注:**文档中的例子使用更短的行长,不超过70,换行符算一个字符。
4.2换行
emsp;当不适合单行时,用下面的几条规则:
- 在逗号处分割
- 在运算符前分割
- 分割有优先级,高级先于低级
- 新的行与上一行对齐(同级)
- 如果上述准则导致了易混淆的代码或者代码被右侧的空白挤扁了,就只用八个空格分割
这里有一些例子:
someMethod(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);
var = someMethod1(longExpression1,
someMethod2(longExpression2,
longExpression3));
下面的两种打断算数的方法。第一种更好,因为打断在被括号的表达式之外,是更高的等级。
longName1 = longName2 * (longName3 + longName4 - longName5)
+ 4 * longname6; // PREFER
longName1 = longName2 * (longName3 + longName4
- longName5) + 4 * longname6; // AVOID
下面是两个方法声明的例子。第一种是规范的情况。第二种将第二行和第三行如果规范化缩进,将会让代码过于靠右,所以用8个空格缩进。
//CONVENTIONAL INDENTATION
someMethod(int anArg, Object anotherArg, String yetAnotherArg,
Object andStillAnother) {
...
}
//INDENT 8 SPACES TO AVOID VERY DEEP INDENTS
private static synchronized horkingLongMethodName(int anArg,
Object anotherArg, String yetAnotherArg,
Object andStillAnother) {
...
}
对于if语句的换行应该用8-space规则,因为常规方法不易分辨主体(body):
//DON'T USE THIS INDENTATION
if ((condition1 && condition2)
|| (condition3 && condition4)
||!(condition5 && condition6)) { //BAD WRAPS
doSomethingAboutIt(); //MAKE THIS LINE EASY TO MISS
}
//USE THIS INDENTATION INSTEAD
if ((condition1 && condition2)
|| (condition3 && condition4)
||!(condition5 && condition6)) {
doSomethingAboutIt();
}
//OR USE THIS
if ((condition1 && condition2) || (condition3 && condition4)
||!(condition5 && condition6)) {
doSomethingAboutIt();
}
对于三元的表达式的方法:
alpha = (aLongBooleanExpression) ? beta : gamma;
alpha = (aLongBooleanExpression) ? beta
: gamma;
alpha = (aLongBooleanExpression)
? beta
: gamma;
5.注释
Java程序含有两种注释:实现注释(Implement comments)和文档注释(documentation comments)。实现注释与c++相同,用/…/和//分割,文档注释“/**…*/”
只用于java中,文档注释能够利用javadoc工具生成HTML文件。
实现注释是用于特定的方法实现,文档注释在实现代码之外,能够被开发人员读到并明确谁有必要使用源代码。
注释提供代码的概况并提供在代码中不能够看出的额外信息。注释只包含帮助阅读和理解代码的信息。举例来说,代码在哪个目录中、由哪个包创建不必作为注释出现。
不普通和和不明显的设计是应该的,但是应该避免重复表示信息。注释应该容易与代码区分。总之,避免随着代码增多,避免代码与注释分离。
**注:**注释的频率有时反应不好的代码质量。当你感到应该添加注释时,考虑重写代码使代码更加啊整洁。
注释不应该大段地被星号和其他字符包围
注释不应该包含换页符和回车
5.1实现注释格式
程序有4种实现注释:块、单行
5.1.1块
用来描述文件、方法、数据结构和算法。块代码可能会被用在每个文件或方法的开头,它们也可以用在方法内等地方。在函数或方法内部的块注释应该首行缩进至与它所描述的代码同级。
注释块应该先于其余代码一个空行。
/*
* Here is a block comment.
*/
/*-indent
<blockquote>/*-
* Here is a block comment with some very special
* formatting that I want indent(1) to ignore.
*
* one
* two
* three
*/
**注:**缩进策略与前面介绍的相同。
5.1.2单行注释
短的单行注释在代码之前,如果注释不能在一行中写下,那就遵循块注释的风格。一个单行注释必须以一个空行为前导。
if (condition) {
/* Handle the condition. */
...
}
5.1.3尾端注释(trailing comments)
尾端注释与代码出现在同一行,但必须挪动足够离远语句以便分辨。对于一大段代码中不止一行代码需要注释,那么注释的缩进应该用相同的tab setting。
if (a == 2) {
return TRUE; /* special case */
} else {
return isPrime(a); /* works only for odd a */
}
5.1.4行尾注释
//用来注释一行或部分行,不应该多行连续注释说明文档;然而,可以多行连续注释代码段。
if (foo > 1) {
// Do a double-flip.
...
}
else {
return false; // Explain why here.
}
//if (bar > 1) {
//
// // Do a triple-flip.
// ...
//}
//else {
// return false;
//}
5.2 文档注释
如何写文档注释(@return, @param, @see)
/**
* Returns an Image object that can then be painted on the screen.
* The url argument must specify an absolute {@link URL}. The name
* argument is a specifier that is relative to the url argument.
* <p>
* This method always returns immediately, whether or not the
* image exists. When this applet attempts to draw the image on
* the screen, the data will be loaded. The graphics primitives
* that draw the image will incrementally paint on the screen.
*
* @param url an absolute URL giving the base location of the image
* @param name the location of the image, relative to the url argument
* @return the image at the specified URL
* @see Image
*/
public Image getImage(URL url, String name) {
try {
return getImage(new URL(url, name));
} catch (MalformedURLException e) {
return null;
}
}
注意类和接口前面的的注释不缩进,(/**)不缩进,但随后的文档注释应该缩进一个空格(与星号对齐)成员包括构造器,首行缩进4个空格,其后缩进5个空格。
当不适合用文档注释时,可以用实现注释代替注释后一行紧跟着它的声明。
6.声明
6.1每行的数量
推荐一行一个声明,因为这样便于注释。换句话说,
int level; // indentation level
int size; // size of table
好于
int level, size;
不要把不同的类型放在同一行,例如:
int foo, fooarray[]; //WRONG!
**注:**可以用tabs代替空格
int level; // indentation level
int size; // size of table
Object currentEntry; // currently selected table entry
6.2初始化
尽量在声明的地方初始化,除非需要经历计算。
6.3位置
在块开始的地方进行声明(被花括号包围)。不要在用到时才进行初始化,那样会迷惑不敏感的程序员,阻碍一定范围内代码的可移植性。
void myMethod() {
int int1 = 0; // beginning of method block
if (condition) {
int int2 = 0; // beginning of "if" block
...
}
}
</blockquote>
显然循环是不同的:
for (int i = 0; i < maxLoops; i++) { ... }
</blockquote>
避免隐藏更高级别声明的本地声明,例如,不能够在内部块中声明相同的变量名。
int count;
...
myMethod() {
if (condition) {
int count = 0; // AVOID!
...
}
...
}
6.4类和接口的声明
下面是一些规则:
- 方法名与(之间没有空格
- {与声明语句同一行
- }独自一行,如果块内没有语句,那么}紧接着{;
class Sample extends Object {
int ivar1;
int ivar2;
Sample(int i, int j) {
ivar1 = i;
ivar2 = j;
}
int emptyMethod() {}
...
}
方法被空行分割
7.语句
7.1简单语句
一行最多含有一条语句
argv++; // Correct
argc--; // Correct
argv++; argc--; // AVOID!
7.2复合语句
复合语句是包含一系列的被“{}”包含的块
- 被包围语句比复合语句深入一个等级
- 前花括号紧接着复合语句,后花括号与复合语句开头对齐
- 单行也应该加花括号
7.3返回语句
尽量不用括号
return;
return myDisk.size();
return (size ? size : defaultSize);
7.4if else
if (condition) {
statements;
}
if (condition) {
statements;
} else {
statements;
}
if (condition) {
statements;
} else if (condition) {
statements;
} else {
statements;
}
避免
if (condition) //AVOID! THIS OMITS THE BRACES {}!
statement;
7.5for语句
for (initialization; condition; update) {
statements;
}
空循环体
for (initialization; condition; update);
7.6while语句
while (condition) {
statements;
}
空循环体
while (condition);
7.7do-while语句
do {
statements;
} while (condition);
7.8 switch语句
switch (condition) {
case ABC:
statements;
/* falls through */
case DEF:
statements;
break;
case XYZ:
statements;
break;
default:
statements;
break;
}
7.9 try-catch Statements
try {
statements;
} catch (ExceptionClass e) {
statements;
} finally {
statements;
}
8.空白
8.1空行
两行空白:
- 源文件的节
- 类与接口的定义
一行空白:
- 方法间
- 本地方法变量和第一个语句间
- 一段代码与单行注释
- 在逻辑块间增加可读性
8.2空格
- 关键字与括号之间需要一个空格
while (true) {
...
}
- 逗号之后
- 所有的二元运算符
a += c + d;
a = (a + b) / (c * d);
while (d++ = s++) {
n++;
}
printSize("size is " + foo + "\n");
- for语句之间的表达式用空格分割
for (expr1; expr2; expr3)
- 转化之后接一个空格
myMethod((byte) aNum, (Object) x);
myMethod((int) (cp + 5), ((int) (i + 3))
+ 1);
9.命名规范
Packages:全为小写字母
com.sun.eng
com.apple.quicktime.v2
edu.cmu.cs.bovik.cheese
Classes:类名应该是名词,大小写混合,简单并且描述性好,避免使用首字母缩略,除非缩写形式被更加广泛的使用
class Raster;
class ImageSprite;
Interfaces:和类名一样
Methods:方法名应该为动词,小写字母开头,大小写混合
Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.
Variables:变量名要短小并且有实际意义,应该是帮助记忆的词汇单个字母的变量名应该避免,除非很快抛弃( i, j, k, m, and n for integers; c, d, and e for characters.)
Constants:
static final int MIN_WIDTH = 4;
static final int MAX_WIDTH = 999;
static final int GET_THE_CPU = 1;
10.编程实践
10.1获取对象和类的变量
不要无缘无故地将任何变量或类的变量为public,实例对象不需要明确地设置和频繁地获取,就像方法调用的副作用一样。
如果用struct,那么久可以都定义为public。
10.2对类中变量和方法的的索引
避免用一个对象来获取类的变量和方法。用类名代替,举例:
classMethod(); //OK
AClass.classMethod(); //OK
anObject.classMethod(); //AVOID!
10.3常量
数字常量不应该直接编码,除了-1,0,和1,能够在for语句中充当计数器。
10.4变量赋值
避免给多个变量在一行中赋相同的值。那是不易阅读的。
Example:
fooBar.fChar = barFoo.lchar = 'c'; // AVOID!
避免在易于与等号混淆的地方用到赋值符号。
if (c++ = d++) { // AVOID! (Java disallows)
...
}
</blockquote>
应该写为
if ((c++ = d++) != 0) {
...
}
不要将赋值语句镶嵌以提升运行性能。这是编译器的工作(compiler)。Example:
d = (a = b + c) + r; // AVOID!
</blockquote>
应该写为:
a = b + c;
d = a + r;
10.5混杂的 联系
10.5.1括号
即使优先级是很清楚的,也应该加入括号,确保阅读代码的人也能明白优先级。
if (a == b && c == d) // AVOID!
if ((a == b) && (c == d)) // RIGHT
10.5.2返回值
让你代码的结构复合期望
if (
booleanExpression) {
return true;
} else {
return false;
}
应该写为:
return
booleanExpression;
if (condition) {
return x;
}
return y;
应该写为:
return (condition ? x : y);
10.5.3在‘?’之前的表达式
当?前的表达是一个二元运算时,应该用括号。Example:
(x >= 0) ? x : -x;
10.5.4特殊注释
用XXX在注释中来标记有些东西是假的但是可以工作。用FIXME来 标记有问题的。
11.代码举例
/*
* @(#)Blah.java 1.82 99/03/18
*
* Copyright (c) 1994-1999 Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*/
package java.blah;
import java.blah.blahdy.BlahBlah;
/**
*
Class description goes here.
*
* @version
1.82 18 Mar 1999 * @author
Firstname Lastname */
public class Blah extends SomeClass {
/* A class implementation comment can go here. */
/**
classVar1 documentation comment */
public static int classVar1;
/**
*
classVar2 documentation comment that happens to be *
more than one line long */
private static Object classVar2;
/**
instanceVar1 documentation comment */
public Object instanceVar1;
/**
instanceVar2 documentation comment */
protected int instanceVar2;
/**
instanceVar3 documentation comment */
private Object[] instanceVar3;
/**
* ...
constructor Blah documentation comment... */
public Blah() {
// ...implementation goes here... }
/**
* ...
method doSomething documentation comment... */
public void doSomething() {
// ...implementation goes here... }
/**
* ...method doSomethingElse
documentation comment... * @param someParam
description */
public void doSomethingElse(Object someParam) {
// ...implementation goes here... }
}