《JAVA提高代码效率的方法.ppt》由会员分享,可在线阅读,更多相关《JAVA提高代码效率的方法.ppt(29页珍藏版)》请在三一办公上搜索。
1、提高代码效率的方法,优化循环体,循环是比较重复运行的地方,如果循环次数很大,循环体内不好的代码对效率的影响就会被放大而变的突出。让我们看看下面的代码片:.Vector vect=new Vector(1000);.for(int i=0;ivect.size();i+).for循环部分改写成:int size=vect.size();for(int i=0;i size;i+).如果size=1000,就可以减少1000次size()的系统调用开销,避免了循环体重复调用。未优化耗时:780309优化后耗时:624430,少用NEW初始化一个实例,尽量少用new来初始化一个类的实例,当一个对象是
2、用new进行初始化时,其构造函数链的所有构造函数都被调用到,所以new操作符是很消耗系统资源的,new一个对象耗时往往是局部变量赋值耗时的上千倍。同时,当生成对象后,系统还要花时间进行垃圾回收和处理。当new创建对象不可避免时,注意避免多次的使用new初始化一个对象。尽量在使用时再创建该对象。如:NewObject object=new NewObject();int value;if(i0)value=object.getValue();修改为:int value;if(i 0)NewObject object=new NewObject();value=object.getValue();
3、另外,应该尽量重复使用一个对象,而不是声明新的同类对象。一个重用对象的方法是改变对象的值,如可以通过setValue之类的方法改变对象的变量达到重用的目的。,在Java中,一切都是对象,如果有方法(Method)调用,处理器先要检查该方法是属于哪个对象,该对象是否有效,对象属于什么类型,然后选择合适的方法并调用。可以减少方法的调用,同样一个方法:int i=0;.CallMethod(i);public void CallMethod(int i)if(i=0)return;./其他处理可修改为:int i=0;.if(i=0)CallMethod(i);不影响可读性等情况下,可以把几个小的方
4、法合成一个大的方法。另外,在方法前加上final,private关键字有利于编译器的优化,选择合适的方法调用,尽量使用局部变量,调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。例子:public class USER private int _sum;private static int _staticSum;void getSum(int values)for(int i=0;i values.length;i+)_sum+
5、=valuesi;/violation.更正:如果可能,请使用局部变量作为你经常访问的变量。你可以按下面的方法来修改getSum()方法:void getSum(int values)int sum=_sum;/temporary local variable.for(int i=0;i values.length;i+)sum+=valuesi;_sum=sum;,STRING与STRINGBUFFER的使用技巧,1、字符串在JAVA中被广泛的使用,但是由于String 对象是不可改变的,所以如果我们试图将两个String对象相加的时候,它实际的执行是产生一个中间对象StringBuffer
6、,并调用它的append()法来进行相加的,最后调用StringBufffer的toString()方法来返回一个String的对象,如果只是一般的相加差别不大,但是如果是在循环中,性能差距就较明显注:String s=“a”+“b”+“c”,实际上在编译后是String s=“abc”,执行时不存在相加问题 2、在字符串相加的时候,如果该字符串只有一个字符的话 如:String str=s+“d”应该换作 string=s+d来执行。3、由于在创建一个StringBuffer对象时,StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重
7、新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,如果可以的话,在创建StringBuffer的时候应指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。,返回,STRING与STRINGBUFFER的使用技巧,尽可能的使用JAVA自身提供的API,用JAVA自身的System.arraycopy方法明显省时,不要重复初始化变量,默认情况下,调用类的构造函数时,Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和double变量设置成0.0,逻辑值设置成false。当
8、一个类从另一个类派生时,这一点尤其应该注意,因为用new关键词创建一个对象时,构造函数链中的所有构造函数都会被自动调用。,避免不需要的造型操作,所有的类都是直接或者间接继承自Object。同样,所有的子类也都隐含的“等于”其父类。那么,由子类造型至父类的操作就是不必要的了。例子:class UNC String _id=UNC;class Dog extends UNC void method()Dog dog=new Dog();UNC animal=(UNC)dog;/not necessary.Object o=(Object)dog;/not necessary.更正:class Do
9、g extends UNC void method()Dog dog=new Dog();UNC animal=dog;Object o=dog;,如果只是查找单个字符的话,用CHARAT()代替STARTSWITH(),用一个字符作为参数调用startsWith()也会工作的很好,但从性能角度上来看,调用charAt更好 例子:public class PCTS private void method(String s)if(s.startsWith(a)/violation/.更正 将startsWith()替换成charAt().public class PCTS private voi
10、d method(String s)if(a=s.charAt(0)/.,不要在循环中调用SYNCHRONIZED(同步)方法,方法的同步需要消耗相当大的资源,在一个循环中调用它绝对不是一个好主意。例子:import java.util.Vector;public class SYN public synchronized void method(Object o)private void test()for(int i=0;i vector.size();i+)method(vector.elementAt(i);/violation private Vector vector=new Ve
11、ctor(5,5);,不要在循环中调用SYNCHRONIZED(同步)方法,更正:不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式:import java.util.Vector;public class SYN public void method(Object o)private void test()synchronized/在一个同步块中执行非同步方法 for(int i=0;i vector.size();i+)method(vector.elementAt(i);private Vector vector=new Vector(5,5);,ORACLE的SQL语句尽量使用
12、大写,在JAVA+ORACLE 的应用系统开发中,java中内嵌的SQL语句尽量使用大写的形式,以减轻ORACLE解析器的解析负担。,减少I/O操作,尽量减少I/O操作:输入/输出(I/O)包括很多方面,我们知道,进行I/O操作是很消耗系统资源的。程序中应该尽量少用I/O操作。使用时可以注意:.合理控制输出函数System.out.println()对于大多时候是有用的,特别是系统调试的时候,但也会产生大量的信息出现在控制台和日志上,同时输出时,有序列化和同步的过程,造成了开销。特别是在发行版中,要合理的控制输出,可以在项目开发时,设计好一个Debug的工具类,在该类中可以实现输出开关,输出的
13、级别,根据不同的情况进行不同的输出的控制。尽量使用缓存:读写内存要比读写硬盘上的文件要快很多,应尽可能使用缓冲,以便直接从内存中读取数据。尽可能使用带有Buffer的类代替没有Buffer的类,如可以用BufferedReader 代替Reader,用BufferedWriter代替Writer来进行处理I/O操作。同样可以用BufferedInputStream代替InputStream都可以获得性能的提高,即时关闭I/O流操作,Java 编程过程中,I/O流操作时务必小心,在使用完毕后,及时关闭以释放资源。因为对这些大对象的操作会造成系统大的开销,稍有不慎,会导致严重的后果。,在FINAL
14、LY块中关闭STREAM,程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。例子:import java.io.*;public class CS public static void main(String args)CS cs=new CS();cs.method();public void method()try FileInputStream fis=new FileInputStream(CS.java);int count=0;while(fis.read()!=-1)count
15、+;System.out.println(count);fis.close();catch(FileNotFoundException e1)catch(IOException e2)更正:在最后一个catch后添加一个finally块,对象使用完毕应手动置成NULL,由于JVM的有其自身的GC机制,不需要程序开发者的过多考虑,从一定程度上减轻了开发者负担,但同时也遗漏了隐患,过分的创建对象会消耗系统的大量内存,严重时会导致内存泄露,因此,保证过期对象的及时回收具有重要意义。JVM回收垃圾的条件是:对象不在被引用;然而,JVM的GC并非十分的机智,即使对象满足了垃圾回收的条件也不一定会被立即回
16、收。所以,建议我们在对象使用完毕,应手动置成null。,慎用异常,异常对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。异常只能用于错误处理,不应该用来控制程序流程。,尽量不要在循环中使用 TRY CATCH,Try catch()如无特殊要求,应把其放置在最外层。比如数据回滚,集合类优化问题,集合类在此Java编程中被广泛地使用,一个集合类就是将一组对
17、象组装成一个对象Java的集合类框架由一些接口(如Collection、List、Set、Map)和一些为通用目的而实现的类(如Vector,ArrayList、Hashtable等等)组成,这些类里,有些提供了某种排序算法,有的提供了同步的方法,有如此多的集合类,在具体使用过程中,我们如何根据自己的需要选择合适的集合类,将对程序的性能产生很大的影响,下面将一些常用的类进行比较:Vector和ArrayList Vector和ArrayList在使用上非常相似,都可用来表示一组数量可变的对象应用的集合,并且可以随机地访问其中的元素。它们的区别如下:1、Vector的方法都是同步的(Synchr
18、onized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好.2、当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样ArrayList就有利于节约内存空间。Hashtable和HashMap 它们的性能方面的比较类似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。当它们中的元素超过它的初始大小时,都会将它的容量翻倍。,ArrayList和LinkedList
19、 对于处理一列数据项,Java提供了两个类ArrayList和LinkedList,ArrayList的内部实现是基于内部数组Object,所以从概念上讲,它更象数组,但LinkedList的内部实现是基于一组连接的记录,所以,它更象一个链表结构,所以,它们在性能上有很大的差别。(1)在ArrayList的前面或中间插入数据时,你必须将其后的所有数据相应的后移,这样必然要花费较多时间,所以,当你的操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能。(2)访问链表中的某个元素时,就必须从链表的一端开始沿着连接方向一个一个元素
20、地去查找,直到找到所需的元素为止,所以,当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。注意:在Java集合框架中的大部分类的大小是可以随着元素个数的增加而相应的增加的,我们似乎不用关心它的初始大小,但如果我们考虑类的性能问题时,就一定要考虑尽可能地设置好集合对象的初始大小,这将大大提高代码的性能,比如,Hashtable缺省的初始大小为11,载入因子为0.75,即如果其中的元素个数超过7个,它就必须增加大小并重新组织元素,所以,如果你知道在创建一个新的Hashtable对象时就知道元素的确切数目如为12,那么,就应将其初始大小
21、设为12/0.75=16,这样,就可以避免重新组织内存并增加大小。(默认Vector ArrayList 10个大小,Hashtable 11,HashMap 16),集合类优化问题,返回,不用保存太多的信息在HTTPSESSION中,很多时候,存储一些对象在HttpSession中是有必要的,可以加快系统的开发,如网上商店系统会把购物车信息保存在该用户的Session中,但当存储大量的信息或是大的对象在会话中时,是有害的,特别是当系统中用户的访问量很大,对内存的需求就会很高。,不用保存太多的信息在HTTPSESSION中,清除SESSION:通常情况,当达到设定的超时时间时,同时有些Sess
22、ion没有了活动,服务器会释放这些没有活动的Session,.不过这种情况下,特别是多用户并访时,系统内存要维护多个的无效Session。当用户退出时,应该手动释放,回收资源,实现如下:HttpSession theSession=request.getSession();/获取当前Sessionif(theSession!=null)theSession.invalidate();/使该Session失效,在JSP页面中关闭无用的会话,一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(
23、true)这样的语句时才被创建,注意如果JSP没有显示的使用 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session=HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。对于那些无需跟踪会话状态的页面,关闭自动创建的会话可以节省一些资源。使用如下page指令:,JDBC链接池,使用Jdbc链接池为了提高访问数据库的性能,我们还可以使用JDBC 2.0的一些规范和特性,J
24、DBC是占用资源的,在使用数据库连接时可以使用连接池Connection Pooling,避免频繁打开、关闭Connection。而我们知道,获取Connection是比较消耗系统资源的。Connection缓冲池:当一个应用程序关闭一个数据库连接时,这个连接并不真正释放而是被循环利用,建立连接是消耗较大的操作,循环利用连接可以显著的提高性能,因为可以减少新连接的建立。一个通过DataSource获取缓冲池获得连接,并连接到一个CustomerDB数据源的代码演示如下:Context ctx=new InitialContext();DataSource dataSource=(DataSou
25、rce)ctx.lookup(jdbc/CustomerDB);Connection conn=dataSource.getConnection(password,username);,缓存DATASORCE,缓存DataSorce一个DataSource对象代表一个实际的数据源。这个数据源可以是从关系数据库到表格形式的文件,完全依赖于它是怎样实现的,一个数据源对象注册到JNDI名字服务后,应用程序就可以从JNDI服务器上取得该对象,并使用之和数据源建立连接。通过上面的例子,我们知道DataSource是从连接池获得连接的一种方式,通过JNDI方式获得,是占用资源的。为了避免再次的JNDI调用,可以系统中缓存要使用的DataSource。,