改善性能的技巧篇

慎用异常

在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的性能,缓冲配套组件如下:
java操作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方法也不需要生成类的实例,比调用实例方法更为方便、易用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值