《培训资料PPTjava(一).ppt》由会员分享,可在线阅读,更多相关《培训资料PPTjava(一).ppt(31页珍藏版)》请在三一办公上搜索。
1、,Beyond Technology,HTML(Ver1.0)演讲人:安建民,目的与目标,优化JAVA编程,并改善代码编写习惯和技巧对敏捷开发有个初步的认识,课程概述,本课程主要是介绍JAVA语言中比较常用编写技巧和习惯,对JAVA的常见细节进行简要分析简述一下对敏捷开发的理解,第一章:编写习惯第二章:JAVA中的异常 第三章:代码优化 第四章:敏捷开发,目录,良好的编写习惯不但有助于代码的移植和纠错,也有助于不同技术人员之间的协作。有些codingfans叫嚣高水平程序员写的代码旁人从来看不懂,这种叫嚣只能证明他们自己压根不配自称程序员。代码具有良好的可读性,是程序员基本的素质需求。再看看整
2、个linux的搭建,没有规范化和标准化的代码习惯,全球的研发协作是绝对不可想象的。,第一章:编写习惯,注释是软件可读性的具体体现。程序注释量一般占程序编码量的20%,软件工程要求不少于20%。程序注释不能用抽象的语言,类似于处理、循环这样的计算机抽象语言,要精确表达出程序的处理说明。例如:计算净需求、计算第一道工序的加工工时等。避免每行程序都使用注释,可以在一段程序的前面加一段注释,具有明确的处理逻辑。注释必不可少,但也不应过多,不要被动的为写注释而写注释。不要指望通过复杂的注释将程序说明白,如果确实不得不写如此过多的注释才能将程序解释明白,那就意味着你的程序需要进行改动了,1.1 习惯一一
3、注释,以下是四种必要的注释:1、标题、附加说明。2、函数、类等的说明。对几乎每个函数都应有适当的说明,通常加在函数实现之前,在没有函数实现部分的情况下则加在函数原型前,其内容主要是函数的功能、目的、算法等说明,参数说明、返回值说明等,必要时还要有一些如特别的软硬件要求等说明。公用函数、公用类的声明必须由注解说明其使用方法和设计思路,当然选择恰当的命名格式能够帮助你把事情解释得更清楚。3、在代码不明晰或不可移植处必须有一定的说明。4、及少量的其它注释,如自定义变量的注释、代码书写时间,循环条件、判断条件等。,比如与平台相关的任何常量,如行分隔符,文件分隔符,路径分隔符等等,这些常量在不同的平台上
4、是不同的,比如文件分隔符,在UNIX和MAC中是“/”,在windows中是“”,如果要使用这些常量,需要使用jdava.util.Properties类的getProperty方法,如java.util.Properties.getProperty(“file.separator”)可以获得文件分隔符,getProperty(“line.separator”)返回行分隔符,getProperty(“path.separator”)返回路径分隔符。还有,比如系统常量、数值等,尽量写成变量的形式,这样对于以后改动代码,将会带来很大的方便。,1.2 习惯一一 尽量避免硬编码,第二章:JAVA中的异
5、常,什么是异常?异常(exception)应该是异常事件(exceptional event)的缩写。异常定义:异常是一个在程序执行期间发生的事件,它中断正在执行的程序的正常的指令流。当在一个方法中发生错误的时候,这个方法创建一个对象,并且把它传递给运行时系统。这个对象被叫做异常对象,它包含了有关错误的信息,这些信息包括错误的类型和在程序发生错误时的状态。创建一个错误对象并把它传递给运行时系统被叫做抛出异常。,优势1:把规则代码与错误处理代码分离异常处理规定把错误发生时所要的细节工作与程序的主逻辑代码分离。在传统程序中,错误的发现、报告以及处理经常使得代码混乱。例如,思考下面的伪代码,这是一个
6、把整个文件读入内存的方法。readFile open the file;determine its size;allocate that much memory;read the file into memory;close the file;如果将各个步骤采用错误码的形式来进行错误发现、报告和处理工作,代码看起来将会很乱,而且不易读懂,以后修改起来也会很困难。但如果采用异常处理的方式虽然不会节省错误的发现、报告、处理的工作量,但是它们能够帮助你更有效的组织代码。,2.1 异常管理的优势,优势2:向调用堆栈上层传递错误异常处理的第二个优势是向方法的调用堆栈上层传递错误报告的能力。假如readF
7、ile方法是主程序调用的一系列嵌套方法中的第四个方法:方法1调用方法2,方法2调用方法3,方法3调用readFile,还假如method1是唯一的能够处理readFile方法中所可能发生的错误的方法,那么传统的错误处理技术会强制method2和method3来传递通过readFile调用堆栈所返回的错误代码,直到错误代码传递到method1因为只有method1能够处理这些错误。但如果采用异常方式一个方法能够抛出它内部的任何异常,所以允许一个上层调用堆栈的方法来捕获它。因此只有处理相关错误的方法来处理发现的错误。,优势3:分组和区分错误类型因为所有在程序内部抛出的异常都是对象,异常的分组或分类
8、是类继承的自然结果。在Java平台中一组相关异常类的例子是在java.io中定义的IOException和它的子类。IOException是最普通的IO异常管理类,并且它描述了在执行I/O操作时所发生的任意的错误类型。它的子类描述了一些特殊的错误。例如,FileNotFoundException异常类代表不能在本地磁盘上找到一个文件。一个方法能够编写特殊的异常处理器,catch(FileNotFoundException e),也可以通过在catch子句中所指定的任何异常的超类的一般类型来捕获异常。,其他的一些注意:1、不要在catch 块中作清除工作,如果要做,请放到finally块中;2、
9、不要增加不必要的catch块。例如try/Nifty code here catch(Exception e)throw e;finally/Cleanup code here 完全可以将catch块省略掉。,3.1创建对象时的几个规则:,(1)避免在循环体中创建对象,即使该对象占用内存空间不大;(2)尽量及时使对象符合垃圾回收标准;(3)不要采用过深的继承层次;(4)访问本地变量优于访问类变量;,第三章:代码优化,(1)变量所包含的对象体积较大,占用内存较多;(2)变量所包含的对象生命周期较长;(3)变量所包含的对象数据稳定;(4)该类的对象实例对该变量所包含的对象有共享需求。,3.2建议在
10、以下情况下使用静态变量,3.3使用循环的几个建议,(1)当做数组拷贝时,采用System.arraycopy()方法完成拷贝要比循环拷贝的执行效率高;(2)尽量避免在循环体中调用方法,因为方法调用是比较昂贵的;(3)在没有使用JIT或者HOTSPOT虚拟机时,尽量使用0值作为终结条件的的比较软素,以提高循环语句的性能;(4)避免在做最终条件比较时采用方法返回值的方式进行判断,这样做将增大系统开销;(5)尽量避免在循环体中使用try-catch块,最好在循环体外使用try-catch块以提高系统性能;(6)在多重循环中,如果有可能,尽量将最长的循环放到最内层,最短的循环放在最外层,以减少循环间的
11、切换次数;(7)如果循环体内有if-else类逻辑判断,并且循环次数很大,最好将if-else类逻辑判断移到循环体外,以提高系统性能;,1、使用ArrayList时调用其 ensuerCapacity()方法来预先设置这个数组的大小,提前告诉系统这个数组的容量,可以提高系统的性能。2、String类型的charAt()和length()方法类似,只不过charAt()方法通过指定的索引值获取该处的字符,而length()方法用来获取字符串的长度。如果字符串特别长,采用charAt()逐一获取特定位置的字符是非常耗时的。因为每次获取指定索引位置的字符都要引起新的检索过程,更好的方法是将字符串通过
12、调用toCharArray()方法转化为字符数组,然后通过数组的索引值获取指定位置的字符。3、大多数的JVM在搜索接口列表是都是从后往前搜索的,因此经常使用到的接口最好位于IMPLEMENTS关键字列表的最后面。最好通过Class.forname()动态的装载类。,3.4 其他,4、final用来声明不可覆盖的方法采用final不但可以防止父类中的方法不被子类覆盖,而且还可以加快应用的运行速度、提高系统性能。在某一方法中直接书写处理代码就是内联的调用方式(内联调用的执行速度比通常的函数执行效率要高),当方法被声明为final后,当你编译应用程序时就可以确定该方法的代码,并且编译器可以将该方法的
13、代码展开插入到调用者代码处,因此提高了应用的运行速度,提高了系统效率。,1、移除重复代码方法:将重复的代码提取,组成一个新的方法。,第四章:敏捷开发,2、将注释转化为代码将注释转换为变量名对参数的注释转化为变量名将注释转化为方法的一部分删掉没用的注释将一部分代码重构成方法,用方法名来表达注释的意思抽取出方法,放于另一个类用注释去命名一个已经存在的方法,为什么要删除额外的注释?因为常常没有把代码写清楚,所以我们就找了一个捷径,就是写上注释,注释不够清楚,再写上文档,好,这样程序可以让人看懂了吧。而这样的结果就是,没有人愿意去好好组织代码,让代码看清楚起来,因为他们总觉得加上注释就好了,之后,代码
14、更新了,可是程序员却常常忘了去更新注释(这种情况经常发生,再好的软件工程师都会有这种问题的存在)。过了一段时间,这些过时的注释不仅不能让代码更容易看懂,反而会误导了读代码的人。到了最后,我们剩下的东西就是:本身就不清晰的代码,混上一些不正确的注释。,判断代码的稳定性方法一:先假设一些具体的情况或者需求变动了,然后来看一看,要满足这些新需求,代码是否需要重新修改。方法二:如果发现我们已经第三次修改这些代码了,那么我们就认定这些代码是不稳定的。方法三:如果这段代码是不稳定或者有一些潜在问题的,那么代码往往会包含一些明显的痕迹。当我们感觉出代码异味时我们必须小心谨慎的检查了。,3、除去代码异味,有哪
15、些异味第一种异味:代码用了类别代码(type code)例:class shapefinal int TYPELINE=0;final int TYPERECTANGLE=1;final int TYPECIRCLE=2;int SHAPETYPE;第二种异味:类属性有时候是不用的第三种异味:给变量取一个好一点的名子做不到,因为不同情况下他们有不同的含义第四种异味:当用到switch(或者一大串的if-else if)时,小心了,switch表达式经常是跟类别代码(type code)同时出现的。,消除代码异味怎么去掉类别代码(type code)大多数情况下,为每个类别建立一个子类。(当不同
16、的类别具有不同的行为时)为每种类别创建一个子类。(当类别行为非常相似,或差别反映在值上时)如何去掉一大串if-else if或者switch经常地为了去掉一大串if-then-else if或者switch,我们需要先保证在每个条件分支下的要写的代码是一样的,然后进行抽象,提取。,普遍的代码异味代码重复太多的注释类别代码(type code)switch或者一大串if-else if想给一个变量、方法或者类名取个好名字时,怎么也取不好用类似XXXOtil,XXXXManager和其他的一些命名在变量、方法或者类名中使用这些单词“And”“Or”等。一些实例中的变量有时有用有时没有用。一个类或方
17、法的代码太多或者太长。一个方法有太多的参数两个类都引用了彼此(依赖于彼此),怎么判断一个类需要修整?方法一:当在读一个类的代码时,看看我们会不会觉得这个类“太长了”,“太复杂了”,或者讲的概念“太多了”?如果是这样的话,我们就认定这个类需要修整。方法二:当发现我们已经在第二次或者第三次扩充这个类的时候,我们认定这个类要修整了。这是一个比较“懒惰被动”的方法,但却很有效。,4、保持代码简洁,当我们要让一个类继承自另一个类时,我们一定要再三检查;子类会不会继承了一些他不需要的功能(属性或者方法),如果是的话,我们就得认真再想想:它们之间又没有真正的继承关系,如果没有的话就用代理;有的话将这些不用的
18、功能从基类移到另外一个合适的地方。,5、慎用继承,不合适的依赖让代码很难被重用一般来说,如果一个类A引用了一个类B,当我们想要重用A这个类时,我们就还得将B这个类也加进我们的系统。如果B引用了C,那么B又将C拉了进来。而如果B或者C在一个新的系统中没有意义,或者压根儿不应该存在的情况下,真正我们想要用的A类也用不了了。,6、处理不合适的依赖,怎么判断是“不合适的依赖”方法一:我们先看一下这段代码里面有没有一些互相循环的引用。如:ZipMainFrame引用了ZipEngine这个类,而ZipEngine又引用了ZipMainFrame。我们管这样的类叫“相互依赖”,互相依赖也是一种代码异味,我
19、们就认定这样的代码是不合适的依赖。方法二:在检查代码的时候,我们问自己对于它已经引用的这些类,是它真正要引用的吗?如果不是,则将它们移出或尽量得提取、抽象。方法三:在设计类的时候,我们先预测一个可能会重用这个类的系统。然后再判断,在那样的系统中,这个类能不能被重用?如果你自己都觉得以后的系统不能重用这个类的话,你就断定这个类包含“不合适的依赖了”。方法四:当我们想在一个系统中重用这个类,却发现重用不了时,我们就判断,这个类包含了“不合适的依赖”。这是个“懒惰而被动”却很“有效”的方法。,开闭原则如果我们需要增加新的功能,我们只要增加新的代码,而不是改变原有的,移除switch和类别代码是达到开
20、闭原则的普遍方法。单一职责原则(The Single Responsibility Principle)每一个类都应该只为了一个理由而修改。当一个类包含去许多其他的功能时,很明显违反了单一职责原则。,7、几个原则,里斯科夫替换原则(LSP)表述:子类应该能够代替父类的功能。或者直接点说,我们应该做到,将所有使用父类的地方改成使用子类后,对结果一点影响都没有。或者更直接一点吧,请尽量不用重载,重载是个很坏很坏的主意。依赖反转原则(Dependency Inversion Priciple)抽象不应该依赖于具体,高层的比较抽象的类不用应该依赖于低层的比较具体的类。当这种问题出现的时候,我们应该抽取出更抽象的一个概念,然后让这两个类依赖于抽象出来的概念。,