使用原汁原味的Java语言文档格式.docx
- 文档编号:17249968
- 上传时间:2022-11-29
- 格式:DOCX
- 页数:17
- 大小:26.23KB
使用原汁原味的Java语言文档格式.docx
《使用原汁原味的Java语言文档格式.docx》由会员分享,可在线阅读,更多相关《使用原汁原味的Java语言文档格式.docx(17页珍藏版)》请在冰豆网上搜索。
%f\t%f\n"
F,C);
12.
F=F+x;
13.}
复制代码
清单1中使用的是什么语言?
很显然是C语言—请等一下,让我们来看看完整的程序,如清单2所示:
清单2.Java程序
1.classTest
{
2.
publicstaticvoidmain(Stringargv[]){
3.
floatF,C;
4.
floatmin_tmp,max_tmp,x;
5.
6.
min_tmp=0;
7.
max_tmp=300;
8.
x
9.
F=min_tmp;
while(F<
C=5*(F-32)/9;
13.
printf("
14.
F=F+x;
15.
}
16.
}
17.
18.
privatestaticvoidprintf(Stringformat,Object...args){
19.
System.out.printf(format,args);
20.
21.}
无论您是否相信,清单1和清单2都是使用Java语言编写的。
它们只是以C语言方言(老实说,清单1也确实可以是C代码)编写的Java代码。
这里的几个习语标志着:
编写这段代码的人是以C语言思考的,只是单纯地将其翻译为Java语言:
∙变量是float而非double。
∙所有变量都是在方法上方声明的。
∙初始化紧接声明之后。
∙使用了while循环而非for循环。
∙使用了printf而非println。
∙main()方法的参数名为argv。
∙数组括号紧接参数名之后,而非类型之后。
如果仅仅考虑所编写的这些代码是否能够编译或者是否会得到正确的结果,那么这些方言都不是错误的。
如果分开来看,这几点都并不明显。
但将它们结合在一起,就构成了一段非常古怪的代码,Java程序员难以读懂,就像美国人难以听懂北英格兰人的方言一样。
您使用的此类C语言方言越少,您的代码就会越清晰。
请牢记这一点,下面我们将继续分析C语言程序员暴露自己身份的一些常见方式,并说明如何才能使他们的代码更符合Java程序员的眼光。
命名规范
根据您原本使用的是C、C++还是C#,您可能有一些较为主观的类命名规范。
举例来说,在C#中,类名都是以小写字母开头的,方法名和字段名以大写字母开头。
Java风格则恰好相反。
我没有任何合理的原因能评判一种规范是否比另一种更好,但我了解,混用命名规范会使代码看起来存在严重错误。
这种做法也会导致bug。
如果您知道,每一个全部由大写字母组成的名称都是常量,则会以不同的方式进行处理。
在寻找命名规范与声明类型不匹配之处时,我发现了程序中的许多bug。
Java编程中的基本命名规则非常简单,也值得牢记:
∙类和接口名以大写字母开头,如Frame。
∙方法、字段和本地变量名以小写字母开头,如read()。
∙类、方法和字段名均使用驼峰式大小写风格,如InputStream和readFully()。
∙常量—终态静态字段和临时终态本地变量—全部适用大写字母,并以下划线分隔各词,如MAX_CONNECTIONS。
请勿缩写
像sprintf和nmtkns这样的名称是超级计算机只有32KB内存时代的遗物。
编译器将标识符限制为8个字符或更少,以此来节约内存。
近30年来,这已经不再是需要担心的问题。
如今,再没有任何理由不使用完整拼写的变量和方法名称。
难以解读、无元音字母的变量名清楚地表明这个程序出自一名皈依Java的C程序员之手,请参见清单3:
清单3.缩写的名称
1.for(inti=0;
i<
nr;
i++){
for(intj=0;
j<
nc;
j++){
t[i][j]=s[i][j];
5.}
不缩写、采用驼峰式大小写风格的名称更易读易懂,如清单4所示:
清单4.未缩写的名称更易读
1.for(introw=0;
numRows;
row++){
for(intcolumn=0;
column<
numColumns;
column++){
target[row][column]=source[row][column];
一段代码被阅读的次数要远远超过编写的次数,Java语言为易读性而进行了优化。
C程序员近乎沉迷于难解的代码,而Java程序员则不然。
Java语言将易读性置于简洁性之前。
有一些极为常用的缩写形式,您仍然可以放心使用:
∙max表示最大(maximum)
∙min表示最小(minimum)
∙in表示InputStream
∙out表示OutputStream
∙e或ex表示catch子句中的异常(不用于其他位置)
∙num表示数字(number),仅用作前缀,如numTokens或numHits
∙tmp表示主要在本地使用的临时变量—针对实例,在交换两个值的时候
除此之外(或许还有少数一些例外),您应完整拼写出名称中使用的所有词。
变量声明、初始化和使用(重用)
早期版本的C需要在方法开始处声明所有变量。
这样是为了在编译器中实现一定的优化,允许它在RAM极为有限的环境中运行。
因而,C语言中的方法大多以几行变量声明开头:
1.inti,j,k;
2.doublex,y,z;
3.floatcf[],gh[],jk[];
然而,这种风格也有一些缺陷。
它将变量的声明与其使用分离开来,使代码的易读性降低。
此外,它会为多种不同的用途重用一个本地变量,有可能并非刻意而为。
但若变量持有代码的某个片段无法接受的残值,这可能会带来无法预料的bug。
这一点与C语言中简短而难解的变量名结合在一起,将会后患无穷。
在Java语言(和较新版本的C语言)中,变量可在初次使用或接近初次使用时声明。
在编写Java代码时,请采取这种做法。
这将使您的代码更加安全、更不易出现bug,也更易于阅读。
此外,Java代码通常在声明变量时初始化各变量,而C程序员有时会写出下面这样的代码:
1.inti;
2.i=7;
尽管这在语法上是正确的,但Java程序员永远不会写出这样的代码。
他们会这样写这段代码:
1.inti=7;
这有助于避免因意外使用了未经初始化的变量而导致的bug。
惟一的常见例外是一个变量的作用域需要同时包含try块和catch或finally块。
这往往是由于代码涉及需要在finally块中关闭的输入流和输出流而导致的,如清单5所示:
清单5.异常处理可能会使变量的作用域难以合理设定
1.InputStreamin;
2.try{
in=newFileInputStream("
data.txt"
);
//readfromInputStream
5.}
6.finally{
if(in!
=null){
in.close();
10.}
但这几乎是惟一的异常。
这种风格的最后一种连锁反应就是Java程序员通常每行仅声明一个变量。
例如,他们初始化变量的方法如下:
1.inti=3;
2.intj=8;
3.intk=9;
通常不会写出下面这样的代码:
1.inti=3,j=8,k=9;
这条语句在语法上是正确的,但除非在一种特殊的例外情况下,专业Java程序员是不会这样做的,后文将介绍这种特殊情况。
老式的C程序员甚至可能编写一个四行的代码:
2.i=3;
3.j=8;
4.k=9;
Java风格将声明与初始化结合在一起,因而实际上要更简练一些,只需要三行代码。
将变量置入循环
常见的一种特殊情况就是在循环外部声明变量。
例如,考虑清单6中简单的for循环,其作用是计算斐波那契数列的前20项:
清单6.C程序员喜欢在循环外部声明变量
1.inthigh=1;
2.intlow=1;
3.inttmp;
4.inti;
5.for(i=1;
20;
System.out.println(high);
tmp=high;
high=high+low;
low=tmp;
所有这四个变量都是在循环外声明的,尽管它们仅在循环内部使用,但作用域不止于此。
这容易导致bug,变量可能会在其目标作用域之外被重用。
对于使用常用名的变量来说更是这样,例如i和tmp。
某次使用的值可能会残留下来,并以无法预计的方式干扰后续的代码。
第一项改进(C语言的现代版本也支持这项改进)是将i循环变量的声明移到循环之内,如清单7所示:
清单7.将循环变量移入循环
4.for(inti=1;
9.}
到这里还没有结束,经验丰富的Java程序员还会将tmp变量移入循环,如清单8所示:
清单8.在循环内声明临时变量
3.for(inti=1;
inttmp=high;
8.}
某些极度追求速度而又不够老练的开发人员有时会提出反对意见,认为这种做法导致循环内执行过多操作,而不只是必要的操作,从而降低代码运行速度。
实际上,在运行时,声明根本不会执行。
将声明移动到循环内绝不会给Java平台造成负面的性能影响。
许多程序员,包括许多经验丰富的Java程序员都可能在这里止步。
然而,还有一种不太常见的技巧,将所有变量都移入循环。
您可以在for循环的初始化阶段声明多个变量,只需使用逗号分隔即可,如清单9所示:
清单9.在循环内声明所有变量
1.for(inti=1,high=1,low=1;
high=high+low;
6.}
这已经不仅仅是惯用的流畅代码,而是真正的专业代码。
与C代码相比,Java代码中的for循环更多、while循环更少,原因就在于这种严格限制本地变量作用域的能力。
不要回收变量
上述讨论得出这样一个结论,Java程序员几乎不会为不同的值和对象重用本地变量。
例如,清单10建立了一些按钮及其关联的动作侦听器:
清单10.回收本地变量
1.Buttonb=newButton("
Play"
2.b.addActionListener(newPlayAction());
3.b=newButton("
Pause"
4.b.addActionListener(newPauseAction());
5.b=newButton("
Rewind"
6.b.addActionListener(newRewindAction());
7.b=newButton("
FastForward"
8.b.addActionListener(newFastForwardAction());
9.b=newButton("
Stop"
10.b.addActionListener(newStopAction());
经验丰富的Java程序员会用5个不同的本地变量重写这段代码,如清单11所示:
清单11.未回收的变量
1.Buttonplay=newButton("
2.play.addActionListener(newPlayAction());
3.Buttonpause=newButton("
4.pause.addActionListener(newPauseAction());
5.Buttonrewind=newButton("
6.rewind.addActionListener(newRewindAction());
7.ButtonfastForward=newButton("
8.fastForward.addActionListener(newFastForwardAction());
9.Buttonstop=newButton("
10.stop.addActionListener(newStopAction());
为多个逻辑上不同的值或对象重用一个本地变量容易导致bug。
实际上,本地变量(并非始终是它们指向的对象)并不影响内存和时间问题。
所以不必为此担忧,可以根据您的需要使用多个不同的本地变量。
使用首选原语数据类型
Java语言有八种原语数据类型,但仅使用了其中的六种。
在Java代码中,float比C代码中少得多。
float变量或文字在Java代码中极为罕见,更常用的是double。
使用float的惟一时机就是操纵精度有限的大型多维浮点数字数组,此时存储空间较为重要。
否则使用double即可。
比float更不常见的是short。
我在Java代码中几乎没有见过short变量。
只有惟一的一次(我要警告您,这是极其罕见的情况),读入的外部定义数据格式碰巧包含16位有符号整型类型。
在这种情况下,大多数程序员都会将其作为int读入。
确定私有属性的范围
您是否见过清单22中这种equals()方法?
清单12.C++程序员编写的equals()方法
1.publicclassFoo{
privatedoublex;
publicdoublegetX(){
returnthis.x;
publicbooleanequals(Objecto){
if(oinstanceofFoo){
Foof=(Foo)o;
returnthis.x==f.getX();
returnfalse;
15.}
这个方法在技术上是正确的,但我确信,这个类是由一名保守的C++程序员编写的。
他在一个方法中使用了私有字段x和公共getter方法getX(),实际上是在一行代码之中,这泄漏了他的身份。
在C++中,这种做法是必要的,因为私有属性的范围是对象而不是类。
也就是说,在C++中,同一个类的对象无法看到彼此的私有成员变量。
他们必须使用accessor方法。
在Java语言中,私有属性的范围是类而非对象。
类型同为Foo的两个对象可直接访问对方的私有字段。
某些微妙—往往又不相关—的考虑思路认为,您应该在Java代码中首选直接字段访问而非getter访问,或者反之。
字段访问相对速度较快,但在少数时候,getter访问可能会提供与直接字段访问略有不同的值,特别是在涉及子类的时候。
在Java语言中,没有任何理由在同一行代码中为同一个类的同一个字段同时使用直接字段访问和getter访问。
标点和语法方言
下面是一些与C语言对应部分不同的Java方言,在某些情况下,这样的差异是为了利用某些Java语言特性。
将数组括号紧接于类型之后
Java语言声明数组的方式与C语言中大致相同:
1.intk[];
2.doubletemperature[];
3.Stringnames[];
但Java语言也提供了一种替代性的语法,将数组复括号紧接于类型之后,而不是变量名之后:
1.int[]k;
2.double[]temperatures;
3.String[]names;
大多数Java程序员都采用了第二种风格。
上面的代码表示k的类型是int数组,temperatures的类型是double数组,names的类型是String数组。
同样,与其他本地变量一样,Java程序员习惯在声明时初始化这些变量:
1.int[]k=newint[10];
2.double[]temperatures=newdouble[75];
3.String[]names=newString[32];
1.使用s==null而不是null==s
谨慎的C程序员已经学会了将文字置于比较运算符的左侧。
例如:
1.if(7==x)doSomething();
目标在于避免意外地使用单等号赋值运算符而非双等号比较运算符:
1.if(7=x)doSomething();
若将文字置于左侧,这样的错误就会成为编译时错误。
这项技巧是C语言中一项著名的编程实践。
它能帮助避免出现真正的bug,因为若将文字置于右端,将始终返回true。
然而,不同于C语言,Java语言具有独立的int和boolean类型,赋值运算符返回int,而比较运算符返回boolean。
因而,if(x=7)已经成为编译时错误,就没有必要为比较语句使用不自然的形式if(7==x),流畅的Java程序员不会这样做。
连接字符串而非格式化字符串
多年以来,Java语言一直没有printf()函数。
最终,Java5中增加了这个函数,有些时候能够发挥作用。
具体来说,在您希望将数字格式化为特定宽度或小数点后带有特定位数的形式时,在这种不常见的情况下,格式字符串是一种便捷的字段特定语言。
而C程序员往往在Java代码中过多地使用printf()。
不应使用它取代简单的字符串连接。
1.System.out.println("
Therewere"
+numErrors+"
errorsreported."
优于:
1.System.out.printf("
Therewere%derrorsreported.\n"
numErrors);
变体使用了字符串连接,更易于阅读,在简单的情况下更是如此,此外,由于不存在格式字符串中的占位符和数字或变量参数的类型匹配不当的情况,出现bug的机会也更少。
首选后增量而非前增量
在某些位置,i++和++i之间的差别十分显著。
Java程序员为这些位置定义了一个具体的名称,那就是“bug”。
不应该编写依赖于前增量和后增量之间差异的代码(对于C语言来说也是如此)。
原因在于难以理解、易于出错。
如果您发现,在您编写的代码中两者的差别有重大影响,那么就应该重新将代码组织为独立的语句,使之不再能够影响大局。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 原汁原味 Java 语言
![提示](https://static.bdocx.com/images/bang_tan.gif)