文档章节

Java代码优化

海军战士
 海军战士
发布于 2017/01/09 17:44
字数 2030
阅读 40
收藏 2

系统性能优化一般分为下面几步走:

1、发现问题

    这一步需要先进行一些性能测试,根据测试结果找出不达标的来进一步分析优化。比如:B/S系统可以在浏览器上安装一些插件(我用的是httpwatch),打开浏览器后进入系统,启动插件的功能,点击查询按钮,该插件就会自动记录查询整个过程的耗时,可以方便你后面的分析,下图为httpwatch某个查询的耗时记录:

    根据性能测试结果要写一份性能测试报告为下一步工作提供依据,写性能测试报告一般有以下几点需要写进去:

         a、测试使用数据是否为现场数据

         b、测试使用的客户端是什么配置

         c、服务器数据库端的配置

         d、选择的测试条件

         e、每个功能测试次数,平均耗时为多少

         f、每次查询返回的数据量

         g、数据库里对应表里的数据总量

         h、将测试记录写成文档,对于不达标的记录高亮显示

2、分析问题

    根据测试报告找出不达标的功能进行单独分析,确定存在问题的具体位置,比如是某个方法还是某个功能段导致整体性能不能达标,一般会先大概分析一下整体的代码,然后从外向里添加日志,打印出各方法的执行时间,这样很快就能确定出问题的具体位置,将分析结果写入文档,为下一步提供依据。

3、提出方案

    根据分析结果提出解决方案,然后写成文档提交审批。

4、解决问题

    根据审批通过的文档进行修改,然后测试修改后的结果,符合要求了就可以提交测试部进行最总测试。

5、结果报告

    测试部测试通过后一个优化就算结束了,写好优化文档上传保存。

 

    上面的这几步每一步都很重要,但是真正难点还是在第三步,提出解决方案,代码优化、逻辑优化甚至是数据库的优化都需要有丰富的编程经验,这个不是一下子能做到的需要长期的积累,在项目里不断的实践才能够越做越好,下面我就将一些看到过的优化方法结合自己的工作总结出来以供参考:

 

 

java代码优化

1、循环

通常把大循环放在里面,把小循环放在外面,例如:

for(int i=0; i<10;i++) {  
    for(int j=0; j<1000000;j++)  {   
            ...  
    }  
} 

把与循环index不相关的移到循环的外面,例如:

for(int i=0; terminal=x.length;i<terminal;i++)  {
    x = x/scaleA * scaleB;
}  
//应该该成:  
Double scale = scaleB*scaleA;  
for(int i=0; terminal=x.length;i<terminal;i++)  {
    x = x/scale ;
}

在重要的循环里,消除循环终止判断时的方法调用,例如:

for(int i=0; i<collection.size();i++)  { 
    ... 
}  
//尽量减少对变量的重复计算  
for(int i=0; n=collection.size();i<n;i++)  {
    ...
}  

尽量不要在循环中使用:

Try {  
} catch() {  
}

应把其放置在最外层

循环内不要创建大量的临时变量

for(int i=1;i<=domainCount;i++){  
        ...   
       AuditResult auditResult = new AuditResult();  
        ...  
}  
//这种做法会在内存中保存N份这个对象的引用,会浪费大量的内存空间,改为  
AuditResult auditResult;  
for(int i=1;i<=domainCount;i++){  
        ...   
       auditResult=new AuditResult();  
        ...  
}  

2、字符串

     ■ 消除字符串连接

  ■创建长字符串时,总是使用StringBuffter代替String

  ■预先分配StringBuffer空间 StringBuffer sb = new StringBuffer(5000);

    ■ StringBuffer 和StringBuilder的区别:

    java.lang.StringBuffer线程安全的可变字符序列。一个类似于String 的字符串缓冲区,但不能修改。

    StringBuilder,与该类相比,通常应该优先使用java.lang.StringBuilder类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

3、异常

         ■ 异常只用于单个真正的错误条件,抛出一个异常和执行一个catch代码块花费是很高的(主要由于当创建一个异常时要获得线程栈的一个快照),只当条件真的异常时才抛出一个异常

  ■ 抛出异常首先要创建一个新的对象。

  Throwable接口的构造函数调用名为fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。

  只要有异常被抛出,JVM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。

  异常只能用于错误处理,不应该用来控制程序流程。

  ■使编译器和运行时最优化,将几个方法调用放在一个try/catch块中,而不是为每个方法调用实现几个try/catch块,例如:

try{   
    Some.method1(); //Difficut for java1.4   
}catch(method1Exception e){   
    handle exception 1 // to optimize this code   
}  
try{   
    Some.method2(); //Difficut for java1.4   
}catch(method2Exception e){   
    handle exception 2 // to optimize this code   
}  
try{   
    Some.method3(); //Difficut for java1.4   
}catch(method3Exception e){   
    handle exception 3 // to optimize this code   
}  
//应该写为:  
try{   
    //Difficut for java1.4   
    Some.method1();   
    Some.method2();   
    Some.method3();   
}catch(method1Exception e){   
    handle exception 1   
}catch(method2Exception e){   
    handle exception 2   
}catch(method3Exception e){   
    handle exception 3   
}  

4、尽量指定类的final修饰符

          ■带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。其为String类指定final也防止了人们覆盖length()方法。

  另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。

5、尽量使用局部变量

          ■调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化

6、乘法和除法

for (val = 0; val < 100000; val +=5) {   
    alterX = val * 8;   
    myResult = val * 2;  
}  
//优化后:  
for (val = 0; val < 100000; val += 5) {   
    alterX = val << 3;   
    myResult = val << 1;  
}  

这个还需要看具体情况,并不是所有的乘除法都能这样优化。

7、array(数组) 和 ArrayList的使用

    array([]):最高效;但是其容量固定且无法动态改变;

    ArrayList:容量可动态增长;但牺牲效率;

    基于效率和类型检验,应尽可能使用array,无法确定数组大小时才使用ArrayList。

    ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于ArrayList的许多方法,如Index、IndexOf、Contains、Sort等都是在内部数组的基础上直接调用Array的对应方法。

8、在JAVA + ORACLE的应用系统开发中,java中内嵌的SQL语句尽量使用大写的形式,以减轻ORACLE解析器的解析负担

9、由于JVM的有其自身的GC机制,不需要程序开发者的过多考虑,从一定程度上减轻了开发者负担,但同时也遗漏了隐患,过分的创建对象会消耗系统的大量内存,严重时会导致内存泄露,因此,保证过期对象的及时回收具有重要意义。JVM回收垃圾的条件是:对象不在被引用;然而,JVM的GC并非十分的机智,即使对象满足了垃圾回收的条件也不一定会被立即回收。所以,建议我们在对象使用完毕,应手动置成null,这样也可以提供性能。

10、尽量采用lazy loading 的策略

即在需要的时候才开始创建,例如:

String str = “aaa”;   
if(i == 1) {  
    list.add(str);   
}  
//应替换为:  
if(i == 1) {  
    String str = “aaa”;   
    list.add(str);   
}   

11、在使用同步机制时,应尽量使用方法同步代替代码块同步

12、当复制大量数据时,使用System.arraycopy()命令

© 著作权归作者所有

海军战士
粉丝 20
博文 138
码字总数 132831
作品 0
深圳
私信 提问

暂无文章

线程池之ThreadPoolExecutor使用

ThreadPoolExecutor提供了四个构造方法: ThreadPoolExecutor构造方法.png 我们以最后一个构造方法(参数最多的那个),对其参数进行解释: public ThreadPoolExecutor(int corePoolSize, /...

天王盖地虎626
23分钟前
1
0
小程序登陆流程

http://www.bubuko.com/infodetail-2592845.html

为何不可1995
32分钟前
1
0
Consul+Spring boot的服务注册和服务注销

一图胜千言 先看一看要做事情,需要在Consul上面实现注册中心的功能,并以2个Spring boot项目分别作为生产者,消费者。 Consul 假设已经完成文章《Consul的开发者模式之Docker版》中的所有的...

亚林瓜子
38分钟前
4
0
MySQL高可用之基于Galera复制跨地域节点分布的滥用

mysql使用教程 MySQL高可用之基于Galera复制跨地域节点分布的滥用 2018-11-22 02:15 8335 85 让我们再一次讨论MySQL高可用性(HA)和同步复制。 它是地理上分布区域上一些高可用性参考架构解...

rootliu
48分钟前
1
0
js判断pc还是移动端

var pcyidong =/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent); 如果pcyidong的值为false则用户的浏览器为pc端 如果pcyidong的值为true则用户浏览器为移动端 if (pcyidong =...

流年那么伤
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部