良好的Java风格:第一部分
作者:Thornton Rose
日期:2001年2月22日
翻译:ant21
简介
多年来,作为一名软件开发者和顾问,我看到过各种程序语言编写的大量代码。其中有书写优雅的,也有书写丑陋的,不幸的是很多代码都属于后者。我希望说服你和我的开发伙伴我们应该在代码风格上给予更多的关注,就像我们关注用户界面和应用程序的其它部分那样。这一系列由两部分组成,在第一部分中,我将解释为什么我们应该关心代码看起来到底是什么样子,并向你展示良好Java风格的一些基本要素。
为什么风格如此重要
虽然Java是用来写程序而不是写散文的,但它也是用来表达思想和想法的。而且,除了传递信息,这些思想和想法也必须确实在解决一些问题。也许你会顾虑好的风格或许会像是在浪费时间,但它可以让我们在代码中表达的思想和想法格外的清晰。
这里是使用良好风格的一些理由[来自"Java Code Conventions," Sun Microsystems]:
一个软件产品一生80%的花费是在维护上。
任何软件都几乎不可能一生都由软件的原作者来维护。
好的风格能够提高软件代码的可维护性。
如果软件还附带源码的话,那它应该像产品的其它部分那样结构良好,清晰,专业。
以良好的风格编写代码还有下面这些好处:
提高代码的可阅读性,连贯性和一致性,这样使代码容易理解和维护。
易于跟踪和调试,因为代码是清晰和连贯的。
易于从你或别的程序员停止的地方继续编写代码,特别是经过较长的一段时间以后。
提高代码指南的价值,因为参与者可以更加集中注意力去了解代码正在做什么。
一般原则
以良好的风格编写Java并不困难,但确实需要注意细节。这里是一些应该遵守的一般原则:
使代码清晰并易于阅读。
使代码一致。
使用明显的标识符。
有逻辑地组织文件和类。
每个文件只有一个类(不包括内部类)。
最大行宽在80-90个字符之间。
使用空格和(或)其它易于判断的分隔符。
缩进使用空格而不是制表符。
制表符 vs. 空格
制表符 vs. 空格是一个有关编写代码的严谨问题,我并不想让你认为只有一种正确方式。我赞成使用空格是因为它确保我的代码在我的编辑器里和在你的编辑器里看起来一样,反之亦然。如果你感觉使用空格而不是制表符“就是不对”,那么就用制表符吧。
大括号和缩进
缩进风格(参看,Raymond, "Indent Style")或者大括号("{" 和 "}")和相关的代码缩进是另一个关于编写代码的严谨问题。像Java这种C风格的编程语言,有很多种缩进风格,并且我也不想说它们其中的哪一种就更好一些。在这篇文章的大部分示例代码中,我使用人们常说的K&R风格。如果你不喜欢K&R,那就用另一种风格好了。
注释
你可以有两种类型的注释放到你的Java代码中:Javadoc注释(也叫文档注释)和实现注释。Javadoc注释可以用javadoc工具提取并产生API文档。实现注释用来解释代码的“如何”和“为什么”。使用下面的原则来注释你的Java代码。
在任何允许使用Javadoc注释的地方使用Javadoc注释(最起码用在类和方法上)。
使用块注释而不是行尾(拖尾)注释,除了一些特殊情况,比如变量的声明。
而且,要记住好的注释总是有帮助的;而坏的注释却是令人讨厌的。
例1. 坏的注释风格。
// applyRotAscii() -- Apply ASCII ROT
private void applyRotAscii(){
try{
int rotLength = java/lang/Integer.java.html" target="_blank">Integer.parseInt(rotationLengthField.getText().trim()); // get rot len
RotAscii cipher = new RotAscii(rotLength); // new cipher
textArea.setText(cipher.transform(textArea.getText())); // transform
}catch(java/lang/Exception.java.html" target="_blank">Exception ex){
/* Show exception */
ExceptionDialog.show(this, "Invalid rotation length: ", ex); }
}
例2. 好的注释风格。
/**
* Apply the ASCII rotation cipher to the users text. The length is retrieved
* from the rotation length field, and the users text is retrieved from the
* text area.
*
* @author Thornton Rose
*/
private void applyRotAscii() {
int rotLength = 0; // rotation length
RotAscii cipher = null; // ASCII rotation cipher
try {
// Get rotation length field and convert to integer.
rotLength = java/lang/Integer.java.html" target="_blank">Integer.parseInt(rotationLengthField.getText().trim());
// Create ASCII rotation cipher and transform the users text with it.
cipher = new RotAscii(rotLength);
textArea.setText(cipher.transform(textArea.getText()));
} catch(java/lang/Exception.java.html" target="_blank">Exception ex) {
// Report the exception to the user.
ExceptionDialog.show(this, "Invalid rotation length: ", ex);
}
}
块和声明
使用下面的原则来写块和声明:
每行只放置一个声明。
控制声明的时候总是使用大括号(比如,if)。
考虑在块结束的地方做注释(比如,} //end if),特别是那些长的或者嵌套的块。
把各种变量的声明放在块的开头。
总是初始化变量。
如果想做完美主义者,左对齐变量名。
switch块中缩进case子句。
操作符的前后分别加上空格。
使用if,for,或者while的时候,在"("前面加上空格。
在表达式中使用空格和圆括号以提高可阅读性。
for循环中的变量在应用“把各种变量的声明放在块的开头”的原则时是个例外。循环变量应该在for语句的初始化部分进行声明,比如,for(int i = 0; ...)
在块结束的地方放置一个声明有助于你捕捉到意外删除的结束大括号。有时候,在一个巨大的文件中要想找到它们真的会把你逼疯的。
例3. 坏的块风格。
try{
for(int i=0;i<5;i++){
...
}
int threshold=calculateThreshold();
float variance=(threshold*2.8)-1;
int c=0;
if (threshold<=15) c=calculateCoefficient();
switch(c){
case 1: setCeiling(c*2); break;
case 2: setCeiling(c*3); break;
else: freakOut();
}
}catch(java/lang/Exception.java.html" target="_blank">Exception ex){ ... }
例4. 好的块风格。
try {
int threshold = 0;
float variance = 0.0;
int coefficient = 0;
// Prepare 5 cycles.
for (int i = 0; i < 5; i ++){
prepareCycle(i);
}
// Calculate the threshold and variance.
threshold = calculateThreshold();
variance = (threshold * 2.8) - 1;
// If the threshold is less than the maximum, calculate the coefficient.
// Otherwise, throw an exception.
if (threshold <= MAX_THRESHOLD) {
coefficient = calculateCoefficient();
} else {
throw new java/lang/RuntimeException.java.html" target="_blank">RuntimeException("Threshold exceeded!");
}
// Set the ceiling based on the coefficient.
switch (coefficient) {
case 1:
setCeiling(coefficient * 2);
break;
case 2:
setCeiling(coefficient * 3);
break;
else:
freakOut();
} // end switch
} catch(java/lang/Exception.java.html" target="_blank">Exception ex) {
...
} // end try