慎用异常
在java软件开发中,经常使用try-catch进行错误捕获异常,但是try-catch语句对系统性能而言是非常糟糕的,虽然再一次try-catch中无法察觉它带来的损失,但是,一旦try-catch语句被应用于循环中,就会给系统带来极大的伤害。
使用局部变量
调用方法时,传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。
其他变量,如静态变量、实例变量等,都在堆(heap)创建速度较慢。
位运算代替乘除法
在所有运算中,位运算是最高效的运算。
一维数组代替二维数组
由于数组的随机访问非常好,许多JDK类库,如ArrayList、Vector等都使用了数组作为其底层实现,但是一维数组和二维数组的访问速度是不一样的,一维数组的访问速度要优于二维数组。因此在性能敏感的系统中要使用二维数组的,可以通过可靠的算法,将二维数组转为一维数组在进行处理,以提高系统的响应速度。
二维数组定义:
int [ ][ ] arr=new int [5][3]; 表示五个一维数组,每个一维数组长度是3.这就组成了二维数组,即5行3列。
优化方式:把二维数组用一维数组替换,提取公共变量
这是一个二维数组
public class Demo {
public static void main(String[] args) throws Exception {
int array[][]=new int[10][5];
for(int i=0;i<array.length;i++) {
for(int j=0;j<array[0].length;j++){
array[i][j]=i;
}
}
}
}
把它变成等价的一维数组,并提取公共变量
public class Demo {
public static void main(String[] args) throws Exception {
int array[]=new int[50];
int len=array.length;
for(int i=0;i<len;i++) {
array[i]=i;
}
System.out.print(Arrays.toString(array));
}
}
优化完毕。
计算的时候我们也应该注意,提取重复的表达式、公因式等操作。
展开循环
普通的循环:
public class Demo {
public static void main(String[] args) throws Exception {
int arr[]=new int[10];
for(int i=0;i<10;i++) {
arr[i]=i;
}
System.out.println(Arrays.toString(arr));
}
}
结果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
展开循环
public class Demo {
public static void main(String[] args) throws Exception {
int arr[]=new int[10];
for(int i=0;i<10;i+=2) {
arr[i]=i;
arr[i+1]=i+1;
}
System.out.println(Arrays.toString(arr));
}
}
结果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
展开循环后,系统性能提升。效率提高。
使用arrayCopy
数组复制是一项使用频率很高的功能,JDK中提供了一个高效的API来实现它
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
这个是System下的一个方法。
java本地方法,所以效率更高。以后数组复制就使用这个方法。(不要自己去实现)
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
int arr[]=new int[1000000];
int arrs[]=new int[1000000];
for(int i=0;i<1000000;i+=2) {
arr[i]=i;
arr[i+1]=i+1;
}
for(int j=0;j<arr.length;j++) {
arrs[j]=arr[j];
}
System.out.println(System.currentTimeMillis()-start);
}
}
结果用时:9
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
int arr[]=new int[1000000];
int arrs[]=new int[1000000];
for(int i=0;i<1000000;i+=2) {
arr[i]=i;
arr[i+1]=i+1;
}
System.arraycopy(arr, 0, arrs, 0, 1000000);
System.out.println(System.currentTimeMillis()-start);
}
}
结果用时:6
从结果可以看出小数据量就可以发现差距。所以用本地方法System.arraycopy来进行数组复制,
效率是最好的。
使用Buffer进行I/O操作
除了NIO之外,使用java进行I/O操作有两种基本方式:
- 使用基于InputStream和OutputStream的方式
- 使用Writer和Reader
无论使用哪种方式进行文件I/O,如果能合理的使用缓冲,就能有效的提高I/O的性能,缓冲配套组件如下:
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
String path="d:"+File.separator+"book.txt";
File file=new File(path);
FileOutputStream fos=new FileOutputStream(file);
DataOutputStream dos=new DataOutputStream(fos);
for(int i=0;i<10000;i++) {
dos.write(i);
}
dos.close();
fos.close();
System.out.println(System.currentTimeMillis()-start);
}
}
结果时长:168
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
String path="d:"+File.separator+"book.txt";
File file=new File(path);
FileOutputStream fos=new FileOutputStream(file);
DataOutputStream dos=new DataOutputStream(new BufferedOutputStream(fos));
for(int i=0;i<10000;i++) {
dos.write(i);
}
dos.close();
fos.close();
System.out.println(System.currentTimeMillis()-start);
}
}
加上缓冲之后的时长:1
所以缓冲其实不论是在写文件还是读文件,对性能都有很大的提升。Reader和Writer的实例就不列举了,
使用缓冲效果都很明显。
使用clone()代替new
在java中新建对象实例最常用的方法是 使用new关键字,JDK对new关键字的支持非常好,使用new关键字创建轻量级对象时,速度非常快。但是对于重量级对象,由于对象在构造函数中可能会进行一些复杂且耗时的操作,因此构造函数的执行时间可能会比较长,同时也使得系统无法在短期内或得大量实例,这时,我们可以使用Object.clone()方法。
Object.clone()方法可以绕过对象构造函数,快速复制一个对象实例,由于不需要调用对象构造函数,因此clone方法不会受到构造函数的性能影响,所以快速生成一个实例,但是在默认情况下,clone()方法的生成只是原对象的浅拷贝,如果需要深拷贝,则需要重新实现clone方法。
静态方法代替实例方法
使用static关键字描述的方法为静态方法。在java中由于实例方法需要维护一张类似虚函数表的结构,以实现对多态的支持。与静态方法相比,实例方法的调用,需要更多的资源。因此对于常用的工具类,没有对其进行重载的必要,那么将它们声明为static,便可以加速方法的调用。
对于一些工具类,应该使用static方法实现,这样不仅可以加快函数调用的速度,同时,调用static方法也不需要生成类的实例,比调用实例方法更为方便、易用。