新华兴Android编程规范与范例Word文档格式.docx
《新华兴Android编程规范与范例Word文档格式.docx》由会员分享,可在线阅读,更多相关《新华兴Android编程规范与范例Word文档格式.docx(21页珍藏版)》请在冰豆网上搜索。
文档审批信息:
文档作者:
日期:
格式审核:
孙军杰
内容审核:
张世光
乐凯
廖鹏方
批准:
宋建华
目录
文档说明4
编程规范5
2.1开发人员的编码规范5
2.1.1不要忽略异常5
2.1.2不要捕获顶级的Exception6
2.1.3不要使用Finalizer7
2.1.4使用完全限定Import7
2.2Java语言规范7
2.2.1使用Javadoc标准注释7
2.2.2编写简短的方法9
2.2.3在标准的位置定义字段9
2.2.4限制变量的作用范围9
2.2.5对Import语句排序10
2.2.6使用空格进行缩进10
2.2.7遵守字段命名约定10
2.2.8使用标准的大括号风格11
2.2.9限制代码行的长度11
2.2.10使用标准的JavaAnnotation11
2.2.11缩写成一个单词12
2.2.12使用TODO注释12
2.2.13慎用日志12
2.2.14保持一致14
2.3Javatest风格规范14
2.4补充14
2.4.1导入注释模板15
2.4.2导入格式化模板15
2.4.3修改用户名15
3.附件17
文档说明
本文档是《CodeStyleGuidelinesforContributors》的译文,英文原文:
文档所支持版本:
Android4.0r1。
编程规范
以下规则并非指导或推荐的性质,而是必须遵守的约定。
Android开发人员,在开发过程中,如果不遵守这些规定,通常不会被别人接受。
已有的代码不必全部遵守这些规定,而在编写新的代码的时候,都应该遵守。
我们遵循标准的Java编码规范,并加入了新的规则。
2.1开发人员的编码规范
2.1.1不要忽略异常
异常被完全忽略是很常见的,比如:
voidsetServerPort(Stringvalue){
try{
serverPort=Integer.parseInt(value);
}catch(NumberFormatExceptione){}
}
你绝对不要这么做。
也许你会认为:
你的代码永远不会碰到这种出错的情况,或者处理异常并不重要,可类似上述忽略异常的代码将会在代码中埋下一颗地雷,说不定哪天它就会炸到某个人了。
你必须在代码中以某种规矩来处理所有的异常。
根据情况的不同,处理的方式也会不一样。
无论何时,空的catch语句都会让人感到不寒而栗。
虽然很多情况下确实是一切正常,但至少你不得不去忧虑它。
在Java中你无法逃离这种恐惧感。
——JamesGosling
可接受的替代方案包括(按照推荐顺序):
●向方法的调用者抛出异常。
voidsetServerPort(Stringvalue)throwsNumberFormatException{
●根据抽象级别抛出新的异常。
voidsetServerPort(Stringvalue)throwsConfigurationException{
}catch(NumberFormatExceptione){
thrownewConfigurationException("
Port"
+value+"
isnotvalid."
);
●优雅地处理错误是在catch{}语句块中替换为合适的值。
/**Setport.Ifvalueisnotavalidnumber,80issubstituted.*/
serverPort=80;
//defaultportforserver
●捕获异常并抛出一个新的RuntimeException。
这种做法比较危险:
只有确信发生该错误时最合适的做法就是崩溃,才会这么做。
/**setport.Ifvalueisnotavalidnumber,die.*/
thrownewRuntimeException("
port"
+value"
isinvalid,"
e);
请记住,最初的异常是传递给构造方法的RuntimeException。
如果代码必须在Java1.3版本下编译,需要忽略该异常。
●最后一招:
如果确信忽略异常比较合适,那就忽略吧,但必须把原因注释出来:
/**Ifvalueisnotavalidnumber,originalportnumberisused.*/
//Methodisdocumentedtojustignoreinvaliduserinput.
//serverPortwilljustbeunchanged.
2.1.2不要捕获顶级的Exception
有时在捕获Exception时偷懒也是很常见的,类似如下的处理方式:
someComplicatedIOFunction();
//maythrowIOException
someComplicatedParsingFunction();
//maythrowParsingException
someComplicatedSecurityFunction();
//maythrowSecurityException
//phew,madeitalltheway
}catch(Exceptione){
//I'
lljustcatchallexceptions
handleError();
//withonegenerichandler!
你不要这么做。
绝大部分情况下,捕获顶级的Exception或Throwable都是不合适的,Throwable更不合适,因为它还包含了Error异常。
这种捕获非常危险。
这意味着本来不必考虑的Exception(包括类似ClassCastException的RuntimeException)被卷入到应用程序级的错误处理中来。
这会让代码运行的错误变得模糊不清。
这意味着,假如别人在你调用的代码中加入了新的异常,编译器将无法帮助你识别出各种不同的错误类型。
绝大部分情况下,无论如何你都不应该用同一种方式来处理各种不同类型的异常。
本规则也有极少数例外情况:
期望捕获所有类型错误的特定的测试代码和顶层代码(为了阻止这些错误在用户界面上显示出来,或者保持批量工作的运行)。
这种情况下可以捕获顶级的Exception(或Throwable)并进行相应的错误处理。
在开始之前,你应该非常仔细地考虑一下,并在注释中解释清楚为什么这么做是安全的。
比捕获顶级Exception更好的方案:
●分开捕获每一种异常,在一条try语句后面跟随多个catch
语句块。
这样可能会有点别扭,但总比捕获所有Exception要好些。
请小心别在catch语句块中重复执行大量的代码。
●重新组织一下代码,使用多个try块,使错误处理的粒度更细一些。
把IO从解析内容的代码中分离出来,根据各自的情况进行单独的错误处理。
●再次抛出异常。
很多时候在你这个级别根本就没必要捕获这个异常,只要让方法抛出该异常即可。
请记住:
异常是你的朋友!
当编译器指出你没有捕获某个异常时,请不要皱眉头。
而应该微笑:
编译器帮助你找到了代码中的运行时(runtime)问题。
2.1.3不要使用Finalizer
Finalizer提供了一个机会,可以让对象被垃圾回收器回收时执行一些代码。
优点:
便于执行清理工作,特别是针对外部资源。
缺点:
调用finalizer的时机并不确定,甚至根本就不会调用。
结论:
我们不要使用finalizers。
大多数情况下,可以用优秀的异常处理代码来执行那些要放入finalizer的工作。
如果确实是需要使用finalizer,那就定义一个close()方法(或类似的方法),并且在文档中准确地记录下需要调用该方法的时机。
相关例程可以参见InputStream。
这种情况下还是适合使用finalizer的,但不需要在finalizer中输出日志信息,因为日志不能因为这个而被撑爆。
2.1.4使用完全限定Import
当需要使用foo包中的Bar类时,存在两种可能的import方式:
1.
importfoo.*;
可能会减少import语句。
2.
importfoo.Bar;
实际用到的类一清二楚。
代码的可读性更好,便于维护。
用后一种写法来import所有的Android代码。
不过导入java标准库(java.util.*、java.io.*等)
和单元测试代码
(junit.framework.*)时可以例外。
2.2Java语言规范
Android在使用Java类库和工具的时候存在一些约定。
有时这些约定会作出重大变化,可之前的代码也许会用到过时的模板或类库。
如果用到这部分过时的代码,沿用已有的风格就是了(参阅Consistency)。
创建新的组件时就不要再使用过时的类库了。
2.2.1使用Javadoc标准注释
每个文件的开头都应该有一句版权说明。
然后下面应该是package包语句和import语句,每个语句块之间用空行分隔。
然后是类或接口的定义。
在Javadoc注释中,应描述类或接口的用途。
/*
*Copyright(C)2010TheAndroidOpenSourceProject
*
*LicensedundertheApacheLicense,Version2.0(the"
License"
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*http:
//www.apache.org/licenses/LICENSE-2.0
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"
ASIS"
BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
*/
packagecom.android.internal.foo;
importandroid.os.Blah;
importandroid.view.Yada;
importjava.sql.ResultSet;
importjava.sql.SQLException;
/**
*DoesXandYandprovidesanabstractionforZ.
publicclassFoo{
...
每个类和自建的public方法必须包含Javadoc注释,注释至少要包含描述该类或方法用途的语句。
并且该语句应该用第三人称的动词形式来开头。
例如:
/**Returnsthecorrectlyroundedpositivesquarerootofadoublevalue.*/
staticdoublesqrt(doublea){
或
*ConstructsanewStringbyconvertingthespecifiedarrayof
*bytesusingtheplatform'
sdefaultcharacterencoding.
publicString(byte[]bytes){
...
如果所有的Javadoc都会写成“setsFoo”,对于那些无关紧要的类似setFoo()的get和set语句是不必撰写Javadoc的。
如果方法执行了比较复杂的操作(比如执行强制约束或者产生很重要的副作用),那就必须进行注释。
如果“Foo”属性的意义不容易理解,也应该进行注释。
无论是public的还是其它类型的,所有自建的方法都将受益于Javadoc。
public的方法是API的组成部分,因此更需要Javadoc。
Android目前还没有规定自己的Javadoc注释撰写规范,但是应该遵守SunJavadoc约定。
2.2.2编写简短的方法
为了把规模控制在合理范围内,方法应该保持简短和重点突出。
不过,有时较长的方法也是合适的,所以对方法的代码长度并没有硬性的限制。
如果方法代码超过了40行,就该考虑是否可以在不损害程序结构的前提下进行分拆。
2.2.3在标准的位置定义字段
字段应该定义在文件开头,或者紧挨着使用这些字段的方法之前。
2.2.4限制变量的作用范围
局部变量的作用范围应该是限制为最小的(EffectiveJava第29条)。
使用局部变量,可以增加代码的可读性和可维护性,并且降低发生错误的可能性。
每个变量都应该在最小范围的代码块中进行声明,该代码块的大小只要能够包含所有对该变量的使用即可。
应该在第一次用到局部变量的地方对其进行声明。
几乎所有局部变量声明都应该进行初始化。
如果还缺少足够的信息来正确地初始化变量,那就应该推迟声明,直至可以初始化为止。
本规则存在一个例外,就是涉及try-catch语句的情况。
如果变量是用方法的返回值来初始化的,而该方法可能会抛出一个checked异常,那么必须在try块中进行变量声明。
如果需在try块之外使用该变量,那它就必须在try块之前就进行声明了,这时它是不可能进行正确的初始化的。
//Instantiateclasscl,whichrepresentssomesortofSet
Sets=null;
s=(Set)cl.newInstance();
}catch(IllegalAccessExceptione){
thrownewIllegalArgumentException(cl+"
notaccessible"
}catch(InstantiationExceptione){
notinstantiable"
//Exercisetheset
s.addAll(Arrays.asList(args));
但即便是这种情况也是可以避免的,把try-catch
块封装在一个方法内即可:
SetcreateSet(Classcl){
return(Set)cl.newInstance();
Sets=createSet(cl);
除非理由十分充分,否则循环变量都应该在for语句内进行声明,:
for(inti=0;
in;
i++){
doSomething(i);
和
for(Iteratori=c.iterator();
i.hasNext();
){
doSomethingElse(i.next());
2.2.5对Import语句排序
import语句的次序应该如下:
Androidimports
第三方库(com、junit、net、org)
3.
java和javax
为了精确匹配IDE的配置,import顺序应该是:
●在每组内部按字母排序,大写字母排在小写字母的前面。
●每个大组之间应该空一行(android、com、junit、net、org、java、javax)。
原先次序是不作为规范性要求的。
这意味着要么允许IDE改变顺序,要么使用IDE的开发者不得不禁用import自动管理功能并且人工维护import。
这看起来比较糟糕。
每当说起java规范,推荐的规范到处都是。
符合我们要求的差不多就是“选择一个次序并坚持下去。
”于是,我们就选择一个规范,更新规范手册,并让IDE去遵守它。
我们期望:
不必耗费更多的精力,用IDE编码的用户就按照这种规则去import所有的package。
基于以下原因,选定了本项规则:
●导入人员期望最先看到的放在最开始位置(android)
●导入人员期望最后才看到的放在最后(java)
●风格让人容易遵守
●IDE可以遵守
静态import的使用和位置已经成为略带争议的话题。
有些人愿意让静态import和其它import混在一起,另一些人则期望让它们位于其它import之上或者之下。
另外,我们还未提到让所有IDE都遵守同一个次序的方法。
因为大多数人都认为这部分内容并不要紧,只要遵守你的决定并坚持下去即可。
2.2.6使用空格进行缩进
我们的代码块缩进使用4个空格。
我们从不使用制表符tab。
如果存在疑惑,与前后的其它代码保持一致即可。
我们用8个空格作为换行后的缩进,包括函数调用和赋值。
例如这是正确的:
Instrumenti=
someLongexpression_r(that,wouldNotFit,on,one,line);
而这是错误的:
2.2.7遵守字段命名约定
●非public的、非static的字段名称以m开头(对于需要使用Setter和Getter的除外)。
●static字段名称以s开头。
●其它字段以小写字母开头。
●publicstaticfinal字段(常量)全部字母大写并用下划线分隔。
publicclassMyClass{
publicstaticfinalintSOME_CONSTANT=42;
publicintpublicField;
privatestaticMyClasssSingleton;
intmPackagePrivate;
privateintmPrivate;
protectedintmProtected;
Stringname=null;
/**
*@returnthename
publicSt