综述
程序的性能受到代码质量的直接影响。本篇主要介绍一些代码编写的小技巧和惯例。虽然看起来有些是微不足道的编程技巧,却可能为系统性能带来成倍的提升。
1 慎用异常
在Java开发中,经常使用try-catch进行错误捕获,但是try-catch语句对系统性能而言是非常糟糕的。虽然一次try-catch中,无法察觉到它对性能带来的损失,但是一旦try-catch语句被应用于循环或是遍历体内,就会给系统性能带来极大的伤害。
劣:
@Test
public void test() {
long start = System.currentTimeMillis();
int a = 0;
for(int i=0;i<1000000000;i++){
try {
a++;
}catch (Exception e){
e.printStackTrace();
}
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
运行结果:useTime:10
将try-catch移到循环体外的代码,那么性能就提升了将近一半。
优:
@Test
public void test(){
long start = System.currentTimeMillis();
int a = 0;
try {
for (int i=0;i<1000000000;i++){
a++;
}
}catch (Exception e){
e.printStackTrace();
}
long useTime = System.currentTimeMillis()-start;
System.out.println(useTime);
}
运行结果:useTime:6
2 使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。
劣:
static int aa = 0;
@Test
public void test(){
long start = System.currentTimeMillis();
for (int i=0;i<1000000000;i++){
aa++;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
运行结果:useTime:90
将类的静态变量替换为局部变量:
优:
@Test
public void test() {
long start = System.currentTimeMillis();
int a = 0;
for(int i=0;i<1000000000;i++){
a++;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
运行结果:useTime:6
3 位运算代替乘除法
在所有的运算中,位运算是最为高效的。因此,可以尝试使用位运算代替部分算术运算,来提高系统的运行速度。最典型的就是对于整数的乘除运算优化。
劣:
@Test
public void test() {
long start = System.currentTimeMillis();
int a = 0;
for(int i=0;i<1000000000;i++){
a*=2;
a/=2;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
运行结果:useTime:1329
将循环体中的乘除运算改为等价的位运算。
优:
@Test
public void test(){
long start = System.currentTimeMillis();
int aa = 0;
for (int i=0;i<1000000000;i++){
aa<<=1;
aa>>=1;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
运行结果:useTime:9
4 提取表达式
在软件开发过程中,程序员很容易有意无意地让代码做一些“重复劳动”,在大部分情况下,由于计算机的高速运行,这些“重复劳动”并不会对性能构成太大的威胁,但若希望将系统性能发挥到极致,提取这些“重复劳动”相当有意义。
劣:
@Test
public void testExpression(){
long start = System.currentTimeMillis();
double d = Math.random();
double a = Math.random();
double b = Math.random();
double e = Math.random();
double x,y;
for(int i=0;i<10000000;i++){
x = d*a*b/3*4*a;
y = e*a*b/3*4*a;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
运行结果:useTime:21
两个计算表达式的后半部分完全相同,这也意味着在每次循环中,相同部分的表达式被重新计算了。
优:
@Test
public void testExpression99(){
long start = System.currentTimeMillis();
double d = Math.random();
double a = Math.random();
double b = Math.random();
double e = Math.random();
double p,x,y;
for(int i=0;i<10000000;i++){
p = a*b/3*4*a;
x = d*p;
y = e*p;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
运行结果:useTime:10
5 使用arrayCopy()
数组复制是一项使用频率很高的功能,JDK中提供了一个高效的API来实现它。
例:
@Test
public void testArrayCopy(){
int size = 100000;
int[] array = new int[size];
int[] arraydest = new int[size];
for(int i=0;i<array.length;i++){
array[i] = i;
}
long start = System.currentTimeMillis();
for (int k=0;k<1000;k++){
//进行复制
System.arraycopy(array,0,arraydest,0,size);
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
6 使用Buffer进行I/O操作
除NIO外,使用Java进行I/O操作有两种基本方式;
使用基于InpuStream和OutputStream的方式;
使用Writer和Reader;
无论使用哪种方式进行文件I/O,如果能合理地使用缓冲,就能有效地提高I/O的性能。
InputStream、OutputStream、Writer和Reader配套使用的缓冲组件。