选用一套管理代码格式的简单规则,然后贯彻这些规则 其实现在的 IDE 基本上都有非常标准的代码格式化规则,我们只需要在编写代码的过程中时常格式化代码即可
5.1 格式的目的
代码格式很重要代码格式不可忽略,必须严肃对待代码的可读性会对以后可能产生的修改行为产生深远影响
5.2 垂直格式
每个文件的代码行数不要过多,尽量保持在 100 行以内,尽量不要超过 200 行短文件通常比长文件易于理解
5.2.1 向报纸学习
名称应当简单且一目了然源文件最顶部应该给出高层次概念和算法细节应该往下渐次展开,直至找到源文件最底层的函数和细节
5.2.2 概念间垂直方向上的区隔
每行展现一个表达式或一个子句,每组代码展示一条完整的思路这些思路之间应该用空白行区隔开每个空白行都是一条线索,标识出新的独立概念
5.2.3 垂直方向上的靠近
紧密相关的代码应该互相靠近
5.2.4 垂直距离
对于那些关系密切,放置于同一源文件中的概念,它们之间的区隔应该成为对相互易懂程度有多重要的衡量标准应该避免迫使读者在源文件和类中跳来跳去变量声明应该尽可能的靠近其使用位置,仅限于局部变量循环中的控制变量应该总是在循环语句中声明实体变量应该在类的顶部声明,就是指的全局变量若某个函数调用了另外一个,就应该把它们放到一起,而且调用者应该尽可能的放在被调用者上面
这一点和我平时的习惯有冲突,我一般喜欢把私有的函数从文件底部开始编写,公开的函数从文件顶部开始编写 概念相关的代码应该放到一起,相关性越强,彼此之间的距离就该越短
Good Example
这是 Junit4 的代码片段,这段代码遵循了作者上述描述中的所有规则我一般习惯把被调用的函数放在下面,同时喜欢把私有函数和共有函数区分开
public class Assert {
static public void assertTrue(String message
, boolean condition
) {
if (!condition
) {
fail(message
);
}
}
static public void assertTrue(boolean condition
) {
assertTrue(null
, condition
);
}
static public void assertFalse(String message
, boolean condition
) {
assertTrue(message
, !condtion
);
}
static public void assertFalse(boolean condition
) {
assertFalse(null
, condtion
);
}
}
5.2.5 垂直顺序
被调用的函数应该放在执行调用的函数下面最重要的概念先出来,通过最少细节表述它们,底层细节最后出来
5.3 横向格式
代码长度达到 100 个字符或者 120 个字符是作者认为已经比较长了但作者也说到,现在显示屏越来越大,分辨率越来越高,所以像 100 - 120 个字符的长度也可以接受,但真的不建议更长
5.3.1 水平方向上的区隔与靠近
我们使用空格字符将彼此紧密相关的事物连接到一起也用空格字符把相关性较弱的事物分隔开这些规则现在的 IDE 都会通过格式化代码做到准确无误我个人比较喜欢单行注释后面加一个空格在编写内容,例如 // 这里是注释 ,而不是 //这里是注释
5.3.2 水平对齐
老旧的习惯,没什么用
5.3.3 缩紧
遵循 IDE 规则即可唯一需要注意的是缩紧的实际空格大小,例如 Java 中的一个 Tab 缩紧表示的是 4 个空格,而其他的例如 JS 就是两个空格我习惯于除了 Java 以外,其他的语言都使用两个空格作为一个 Tab 的缩紧
5.3.4 空范围
尽量不要使用将 while 或 for 语句的语句体置为空的写法
5.4 团队规则
一组开发者应当认同一种格式风格,每个成员都应该采用那种风格好的软件系统是由一系列读起来不错的代码文件组成,它们需要拥有一致和顺畅的风格绝对不要用各种不同的风格来编写源代码,这样会增加其复杂度
5.5 鲍勃大叔的格式规则
作者认为下面这段代码是他写的可以作为 最好的编码便准文档的范例我觉得大部分还比较认可,几个小细节跟我习惯性的有点出入
public class CodeAnalyzer implements JavaFileAnalysis {
private int lineCount
;
private int maxLineWidth
;
private int widestLineNumber
;
private LineWidthHistogram lineWidthHistogram
;
private int totalChars
;
public CodeAnalyzer() {
lineWidthHistogram
= new LineWidthHistogram;
}
public static List
<File> findJavaFiles(File parentDirectory
) {
List
<File> files
= new ArrayList<File>();
findJavaFiles(parentDirectory
, files
);
return files
;
}
private static void findJavaFiles(File parentDirectory
, List
<File> files
) {
for (File file
: parentDirectory
.listFiles()) {
if (file
.getName().endsWith(“
.java”
)) {
files
.add(file
);
} else if (file
.isDirectory()) {
findJavaFile(file
, files
);
}
}
}
public void analyzeFile(File javaFile
) throws Exception
{
BufferedReader br
= new BufferedReader(new FileReader(javaFile
));
String line
;
while ((line
= br
.readLine()) != null
) {
measureLine(line
);
}
}
private void measureLine(String line
) {
lineCount
++;
int lineSize
= line
.length();
totalChars
+= lineSize
;
lineWidthHistogram
.addLine(lineSize
, lineCount
);
recordWidestLine(lineSize
);
}
private void recordWidestLine(int lineSize
) {
if (lineSize
> maxLineWidth
) {
maxLineWidth
= lineSize
;
widestLineNumber
= lineCount
;
}
}
public int getLineCount() {
return lineCount
;
}
public int getMaxLineWidth() {
return maxLineWidth
;
}
public int getWidestLineNumber() {
return widestLineNumber
;
}
public LineWidthHistogram
getLineWidthHistogram() {
return lineWidthHistogram
;
}
public double getMeanLineWidth() {
return (double) totalChars
/ lineCount
;
}
public int getMedianLineWidth() {
Integer
[] sortedWidths
= getSortedWidth();
int cumulativeLineCount
= 0;
for (int width
: sortedWidths
) {
cumulativeLineCount
+= lineCountForWidth(width
);
if (cumulativeLineCount
> lineCount
/ 2) {
return width
;
}
}
throw new Error(“Cannot get here”
);
}
private int lineCountForWidth(int width
) {
return lineWidthHistogram
.getLinesForWidth(width
).size();
}
private Integer
[] getSortedWidths() {
Set
<Integer> widths
= lineWidthHistogram
.getWidths();
Integer
[] sortedWidths
= (widths
.toArray(new Integer[0]));
Array
.sort(sortedWidths
);
return sortedWidths
;
}
}