`

Java编程风格

阅读更多
JAVA编程风格简析

很久以来都在体会着JAVA的风格,现在做一简单陈述,希望大家多提宝贵意见。

对于一种好的编程语言,学习它的编程风格是很重要的。每种语言都有自己的编写和注释约定,当然所有语言都建立在最基本的约定之上。编程中最重要的并不是让代码按自己希望的方式运行,而是程序中那种自明的编程风格(这对于程序员的益处相信众多程序员都身有体会)!但这还不够,程序还应该具有可读、相对持久和可维护性。可读性非常重要,因为你不希望自己以前的作品在之后的阅读中给自己留下障碍,当然,更重要的是自己的程序能让其他程序员读懂并且修改。

下面我把工作中所理解的java风格做一简单总结,这是我所理解的好的编程风格和应用中我们应当如何使用java编写自己的代码的小Guide。这并不完全,希望大家帮我陆续总结各自的经验。

一般性概述
好的编程风格固然重要,但是你一定听说过一些程序员的个人风格。其实我们完全不必为那些所谓条条框框所累,但是作为原则是我们至少不能打破这些常规。我们应该在保持自己风格的同时尽量的把自己与编程潜原则靠拢。

可读性很容易达到,比如,让自己的代码缩排排列、名字采用描述性但不要过长(短名应仅仅用在非远程)、特殊名称比如pi应当被定义为final类型。模块性是编程需要注意的另一重点,把代码划分到类里,在类中把功能划分到方法中,别让一个类太大,否则在使用、修改和理解上都会造成不必要的麻烦,方法也一样,如果一个方法长度超过50行,它产生错误的概率将接近100%,尽量把大方法划分为小方法,编程中为避免重复编写,还应尽量调用JAVA标准类库。

尽量避免在写代码和注释时使用不同语言,经常见到论坛有朋友询问诸如在java中调用c、调用php、调用shell之类的问题,其实在编程中,我们应尽量使用一种语言去完成事情。另外就是不必最优化自己的代码,应该选择相对较优的算法就可以了。

类、方法和fields
类应体现出某种物质的基本概念,比如要编程实现“汽车”的组成,那么所有的汽车都可以用类Car实现。这个类应当包括域描述、属性描述和car的状态(color, number of doors, age等)和由car可完成的操作(getColor, setColor等)。为了提高类的可重用性,不要在类中有过多的描述,当然这也会增加错误产生的机会。

类名首字母大写,比如Date, String, Hashtable等 ... ...

类如下定义:(未使用Javadoc做注释):

public class Car {

   /* Instance variables are placed either in the beginning 
    or at the end of the class */

   private int age;
   private Color color;
  
   /* The constructor should be placed in the beginning */

   public Car(int age, Color color) {
this.age = age;
this.color = color;
   }  

   /* Example method */
   public int getAge() {
return age;
   }  
  
   /* The main method is optional, but looks like this. 
    If it exists, it is either the first or the last 
    method in the class */
  
   public static void main(String [] args) {
...

   }
}


注意类名和大括号间的空格!

方法
方法一般定义为public。当然,如果方法仅仅在当前类用到可以定义为private,而如果希望一个子类沿用这个方法则不同,这时候的方法应定义为protected。

java中的方法定义很有趣,它们一般小写字母开头,如果有两个字组成,第二个字的首字母则大写。因此名字的描述性是至关重要的。这使你不用阅读整篇代码来判断这是一个什么方法。在给自己的方法取名时应尽量不要太短或者太长,另一个需要注意的是大多方法使用动词(动宾短语)。

例如:
public void eat() {}
public void eatBananas() {}


Selector(选择器)方法有get前缀,后缀是它们将要get的,比如
public int getBananas() {}


Mutator(存取器)方法则有set前缀,后缀则是他们要set的,比如
public void setBananas(int amount) {}

注意mutators大多无返回值。

方法的参数应当以如下方式给出:
public void aMethod(type parameter1, type parameter2, ... , type parametern) {}


如果参数过长,也可以断开为几行,应对齐向下排列如:
public void aMethod(type parameter1, type parameter2,... , 
                   type parametern, type parameter n+1,... ,
                   type parameterm, type parameter m+1) {}

另外要注意类的左束括号应在方法的右束括号之后而非下一行:

public int aMethod() {
   int i = 0;
   if(i == 0)
System.out.println("success!");
}


为了文件可读性好,还要注意语句最好写在同一行,当然一行写不下是可以断行的,比如行字母超过80。

fields
比如变量,如果不希望它永久有效,应设为private。如果一个变量在类中不发生任何动作(比如数据结构中的node)则可以设置为public,常量一般声明为public。如果不能确定一个变量到底该声明为什么,应暂且声明为private。

field的名字一般使用小写字母,不要使用下横线或其他特殊字符。 如果变量包含两个字,那么第二个字的首字母大写。比如:

int i, j, k;
Date date;
double myField;


常量一般全部大写,也可以包含下横线:

public static final int MAX_SIZE_OF_DATABASE


fields的名字通常为名词。较重要的fields更应具备描述性,比如程序中包含一个游戏的得分,那可以用score来代表。如果变量变化较频繁,那使用一个单一字符来代表就ok了:

i, j, k 通常代表整数
r, t, u, v, w 通常代表实数
x, y, z 通常是并列出现或代表浮点数
s, s1, s2, 通常代表字符串
c, ch 通常代表字符
f, file 通常代表文件
tmp, temp 通常代表临时变量
ctr, cnt, cntr 一般代表计数器(如果i, j, k这些变量已被使用)
dummy, foo, bar 一般代表哑元变量
args 是main-method的主参数名

缩排与换行
每行长度不得超过80字符。如果需要可以折行时,也应当与上一行有共同的缩排距离。代码应如何交错、如何建立新行、在哪里建立允许、哪里不允许都有一些一般约定,缩排空格一般为2个或4个空格。

条件表达式
如果见到如下语法表达式:

if (expr)          
   statement1;
else
   statement2;


代码行向右错排两个空格如上所示。

如果在一个表达式中有超过一条的声明,则需要大括号:

if (expr){
statement1;
statement2;
} else{
statement3;
statement4;
}


有时我们会希望在表达式中使用表达式(比如条件嵌套),这时应注意else表达式,它的位置很容易出错!如例:

if (expr1) {
statement1;
statement2;
} else if (expr2)
statement3;
else if (expr3) {
statement4;
statement5;
} else {
statement6;
statement7;
}


注意大括号位置!

Loops
while-loop语法如下:

while (expr) {
statement1;
statement2;
}


for-loop语法如下:

for (expr1; expr2; expr3){
statement1;
statement2;
}


注意大括号位置!仅一条声明时大括号省略:

while (expr)
statement;

for (expr1; expr2; expr3)
statement;


例如,我们写一个procedure写出1到10这十个数字:

for (i = 1; i <= 10; i++)
System.out.println(i);

try-catch语法形如:

try {
statements;
} catch (ExceptionClass e) {
statements;
}


如果try-catch语句后跟随finally子句则形如:

try {
statements;
} catch (ExceptionClass e) {
statements;
} finally {
statements;
}


新行
每一行最好只阐述一件事情。比如,一行包含一个声明、一个条件语句、一个循环等。不论多小,最好不要一行办两件事及以上。例如不要把一个if表达式或循环语句的主体放置在同一行,这样的表达式断行的易读性会更高。通常,互相协作的代码应放在一起,为保证代码美观可读,我们应将代码的不同代码段放置在不同的段落。不过要牢记断行不要太过分!比如:

public int factorial(int n) {
   int result = 1;
   for(int i = 1; i <= n; i++)
result*=i;

   return result;
}


给自己的代码加入注释
注释就是类的描绘、方法存在的原因、它完成了什么以及它对它其中(变量)的作用域。假定阅读你代码的人已经知道这是什么语言,所以不需要注释语句功能,尽量使用简短而有描述力的注释。

Java有两种类型的注释:

//This is a comment that continues until the end of the line.

/* This is a comment. It goes on and on and on and on and on and on and on
and on and on and on and on and on and on and on and on and on and on and
on and on and on and on and on and on and on and on and ends like this: */

/**
* This is a JavaDoc comment. More about JavaDoc in the next section.
*/


如果在注释中加入注释则会出错:

/* You are not allowed to do anything like this /* because the compiler will
complain, if you are lucky */ DON'T DO THIS! And don't write comments in
upper case either... */

注释应放在它要解释内容上下,这样会让代码更易于理解。

不要注释一些语言的语句功能:
i++;   // Add 1 to i


更不要让自己的代码处于这种状态:

for(int i = 1; i <= n; i++)
/* don't place comments where 
   they don't belong */
result*=i;


较短的注释既可被放在被注释代码上下,而长注释则习惯性的放在代码之上:

/* Comments can be placed before the
block that is to be commented */

for(int i = 1; i <= n; i++)
   result*=i;


或者:
for(int i = 1; i <= n; i++){
   result*=i;                 // short comments can be placed like this
   tmp++;                    // if necessary, they continue here
}


不要写没用的注释:

i++; // change this later

Excuse me,这句肯定是胡扯!

不要写自己都看不懂的注释:

i++;   // BMW


BMW? 如果你能连续十天记住这是什么意思的话,那么你的记忆真是不错了。所以不要写没人能看懂的注释,ok?

最后重申一下:写简短而富于描述性的注释,把它们放在该放的地方,而不要考验你自己的记忆力!


JavaDoc - 文档工具
JavaDoc不仅是另一种给代码加注释的仿佛咱,更是一个文档工具。类、方法和一些重要地方需要用JavaDoc来注释。这并不是说你可以放弃常规的注释,这两者在代码中应该是相辅相成、互相弥补的关系。

类被注释如:

/**
* Car represents cars ... A description of the class
* should be place here. Note that the description begins
* on the second line and that there is a space between 
* the asterix and the text. Next we will add some fields
* indicating who the authors of the class are and
* other useful information. Notice the newline!
*
* @author Jerry Meng
* @version %I%, %G%
*/
public class Car {


注意JavaDoc结束和类开始间无空行。

方法被注释如:

/**
* A description of what the method does...
*
* @param n   a description of the parameter
* @return a description of the return value
*/
public int factorial(int n) {



某些不是全部,被JavaDoc注释区域如:

/**
* Short description of the variable (one line)
*/
type variable;


什么应当使用JavaDoc做注释?如何注释的恰当呢?
可以这样想,JavaDoc中所作的注释都可以在类的文档中看到。所有读这个类的文档的读者都会明白这个类所完成的功能、它包括的方法、如何使用这些方法及方法的返回值。一些作用域,比如public的变量或常量将会一目了然。任何不了解这个类内部结构的人都可以轻松的调用它。这便是你用JavaDoc可以轻松提供的信息。而使用一般注释的地方,一般是给那些可能修改你的类代码的程序员,它们一般描述了类的内部信息和结构。

下面我写一下car的类来描述一个编程风格好的java类应该是怎样的。当然这仅仅是一个小例子(apart from selector and mutator methods),仅仅是在考虑JAVA编程风格上一个参考而已。
import java.awt.Color;

/**
* This is a class representing cars. A car has certain features, such 
* as color, age, number of doors etc and a car can be repainted,
* the tank can be filled etc.
*
* @author Jerry Meng
* @version %I%, %G%
*/
public class Car {

   /**
* The maximum size of the tank in litres. 
*/
   private static final double TANK_SIZE = 100.0;

   /**
* The color of the car.
*/
   private Color color; 

   /**
* The age of the car.
*/
   private int age;             
  
   /**
* The number of doors of the car.
*/
   private int doors;             

   /**
* The amount of gasoline in the tank.
*/
   private double gasoline;  

   /**
* Class constructor, which constructs a brand new, black car with
* five doors and a full tank.
*/
   public Car() {
this(Color.black, 0, 5, TANK_SIZE);
   }
  
   /**
* Class constructor specifying the color, age, number of doors
* and litres of gasoline
* 
* @param color The color of the car
* @param age    The age of the car
* @param doors The number of doors
* @param km    Kilometres driven
* @param gasoline The litres of gasoline
*/
   public Car(Color color, int age, int doors, double gasoline) {
this.color = color;
this.age = age;
this.doors = doors;
this.gasoline = gasoline;
   }
  
   /**
* Returns the color of the car
*/
   public Color getColor() {
return color;
   }

   /**
* Repaints the car (i.e. changes its color)
*/
   public void setColor(Color color) {
this.color = color;
   }
  
   /**
* Returns the age of the car
*/
   public int getAge() {
return age;
   }

   /**
* Returns the number of doors of the car
*/
   public int getDoors() {
return doors;
   }

   /**
* Returns the amount of gasoline in the tank
*/
   public double getGasoline() {
return gasoline;
   }

   /**
* Fills the tank. The amount of gasoline cannot exceed
* the size of the tank. In that case, the tank will be
* filled to the maximum and the rest will run out in
* the sand.
*
* @param gas   The amount of gasoline to put in the tank
*/
   public void setGasoline(double gas) {

if(gasoline + gas <= TANK_SIZE)
   gasoline+=gas;
else 
   gasoline = TANK_SIZE;  
   }
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics