提升Java性能的基本方法

时间:2023-01-23 11:42:41

Java从诞生之日起就被质疑:字节码在JVM中运行是否会比机器码直接运行的效率会 低很多?很多技术高手、权威网站都有类似的测试和争论,从而来表明Java比C (或C++) 更快或效率相同。此类话题我们暂且不表(这类问题的争论没完没了,也许等到我们退休的时候,还想找个活动脑筋的方式,此类问题就会是最好的选择),我们先从如何提髙Java的 性能方面入手,看看怎么做才能让Java程序跑得更快,效率更髙,吞吐量更大。

(1)  不要在循环条件中计算

如果在循环(如for循环、while循环)条件中计算,则每循环一遍就要计算一次,这会 降低系统效率,就比如这样的代码:

//每次循环都要计算count*2

while(i<connt*2){

   //Do Something

}

应该替换为:

//只计算一遍

int total = count * 2;

while(i<total){

  //Do Something

}

(2)   尽可能把变量、方法声明为final static类型

假设要将阿拉伯数字转换为中文数字,其定义如下

public String toChineseNum(int num){

    //中文数字

String[] cns = {"零","壹",”贰”,"卷","肆","伍",”油","柒掮",”玖"};

   return cns[num];

}

每次调用该方法时都会重新生成一个cns数组,注意该数组不会改变,属于不变数组, 在这种情况下,把它声明为类变量,并且加上final static修饰会更合适,在类加载后就生成 了该数组,每次方法调用则不再重新生成数组对象了,这有助于提髙系统性能,代码如下。


//声明为类变量

final static String [] cns = {"零","金","米","卷","律",”伍味",”染”,"相”,"反"};

public String toChineseNum(int num){

   return cns[num];

}

(3)   缩小变量的作用范围

关于变量,能定义在方法内的就定义在方法内,能定义在一个循环体内的就定义在循环体内,能放置在一个try……catch块内的就放置在该块内,其目的是加快GC的回收。

(4)  频繁字符串操作使用StringBuil'der或StringBuiJ'er

虽然String的联接操作(“+”号)已经做了很多优化,但在大量的追加操作上StringBuilder或StringBuffer还是比“ + ”号的性能好很多,例如这样的代码:

String str = "Logfile is ready......"

for (inti = 0; i < max; i++) {

//此处生成三个对象

   str +="log" + i;

}

应该修改为:

StringBuildersb = new StringBuilder(20000);

sb. append ("Log file is ready ");

for (int i = 0; i <max; i++) {
sb.append("log " +i);

}

Stringlog = sb.toString{);

(5)  使用非线性检索

如果在ArrayList中存储了大量的数据,使用indexOf査找元素会比java.utils. Collections. binarySearch的效率低很多,原因是binarySearch是二分捜索法,而indexOf使用的是逐个 元素比对的方法。这里要注意:使用binarySearch搜索时,元素必须进行排序,否则准确性

就不可靠了。

(6)  覆写Exception 的 filllnStackTrace 方法

我们在第8章中提到filllnStackTrace方法是用来记录异常时的栈信息的,这是非常耗时 的动作,如果我们在开发时不需要关注栈信息,则可以覆盖之,如下覆盖filllnStackTrace的 自定义异常会使性能提升10倍以上:

class MyExceptionextends Exception {

public Throwable filllnStackTrace (){

    return  this;

}

(7) 不建立冗余对象

不需要建立的对象就不能建立,说起来很容易,要完全遵循此规则难度就很大了,我们经常就会无意地创建冗余对象,例如这样一段代码:

public void doSomething() {

   //异常信息

String exceptionMsg = ”我出现弁常了,快来就救我!";

try {

    Thread.sleep(10);

} catch (Exception e) {

//转换为自定义运行期异常

throw newMyException(e,exceptionMsg);

  }

}

注意看变量exceptionMsg,这个字符串变量在什么时候会被用到?只有在抛出异常时 它才有用武之地,那它是什么时候创建的呢?只要该方法被调用就创建,不管会不会抛出异常。我们知道异常不是我们的主逻辑,不是我们代码必须或经常要到达的区域,那为了这个 不经常出现的场景就每次都多定义一个字符串变量,合适吗?而且还要占用更多的内存!所以,在catch块中定义exceptionMsg方法才是正道:需要的时候才创建对象。

我们知道运行一段程序需要三种资源:CPU、内存、1/0,提升CPU的处理速度可以加 快代码的执行速度,直接表现就是返回时间缩短了,效率提高了;内存是Java程序必须考虑 的问题,在32位的机器上,一个JVM最多只能使用2GB的内存,而且程序占用的内存越 大,寻址效率也就越低,这也是影响效率的一个因素。I/O是程序展示和存储数据的主要通 道,如果它很缓慢就会影响正常的显示效果。所以我们在编码时需要从这三个方面入手接口(当然了,任何程序优化都是从这三方面入手的)。

Java的基本优化方法非常多,这里不再罗列,相信读者也有自己的小本本,上面所罗列的性能优化方法可能远比这里多,但是随着Java的不断升级,很多看似很正确的优化策略就 逐渐过时了(或者说已经失效了),这一点还需要读者注意。最基本的优化方法就是自我验 证,找出最佳的优化途径,提髙系统性能,不可盲目信任。

35 个 Java 代码性能优化总结