Java性能优化之编程技巧总结

程序的性能受代码质量的直接影响。在本文中,主要介绍一些代码编写的小技巧和惯例,这些技巧有助于在代码级别上提升系统性能

1、慎用异常

Java软件开发中,经常使用 try-catch 进行错误捕获,但是,try-catch 语句对系统性能而言是非常糟糕的。虽然在一次 try-catch中,无法察觉到它对性能带来的损失,但是,一旦try-catch被应用于循环之中,就会给系统性能带来极大的伤害。

以下是一段将try-catch应用于for循环内的示例

public void test() { int a = 0; try { for (int i = 0; i < 1000000; i++) { a = a + 1; System.out.println(i); } } catch (Exception e) { e.printStackTrace(); } }

这段代码我运行时间是 27211 ms。如果将try-catch移到循环体外,那么就能提升系统性能,如下代码

public void test() { int a = 0; for (int i = 0; i < 1000000; i++) { try { a = a + 1; System.out.println(i); } catch (Exception e) { e.printStackTrace(); } } }

运行耗时 15647 ms。可见tyr-catch对系统性能的影响。

2、使用局部环境

调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。

下面是一段测试用例

// private static int a = 0; public static void main(String[] args) { int a = 0; long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { a = a + 1; System.out.println(i); } System.out.println(System.currentTimeMillis() - start); }

运行结果很明显,使用静态变量耗时15677ms,使用局部变量耗时13509ms。由此可见,局部变量的访问速度高于类的成员变量

3、位运算代替乘除法

在所有的运算中,位运算是最为高效的。因此,可以尝试使用位运算代替部分算术运算,来提高系统的运行速度。

比如在HashMap的源码中使用了位运算

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 static final int MAXIMUM_CAPACITY = 1 << 30;

对于整数的乘除运算优化

a*=2 a/=2

用位运算可以写为

a<<=1 a>>=1 4、替换switch

关键字 switch 语句用于多条件判断, switch 语句的功能类似于 if-else 语句,两者性能也差不多。因此,不能说 switch 语句会降低系统的性能。但是,在绝大部分情况下,switch 语句还是有性能提升空间的。

来看下面的例子:

public static void main(String[] args) { long start = System.currentTimeMillis(); int re = 0; for (int i = 0;i<1000000;i++){ re = switchInt(i); System.out.println(re); } System.out.println(System.currentTimeMillis() - start+"毫秒");//17860 } public static int switchInt(int z){ int i = z%10+1; switch (i){ case 1:return 3; case 2:return 6; case 3:return 7; case 4:return 8; case 5:return 10; case 6:return 16; case 7:return 18; case 8:return 44; default:return -1; } }

就分支逻辑而言,这种 switch 模式的性能并不差。但是如果换一种新的思路替代switch,实现相同的程序功能,name性能就能有很大的提升空间。

public static void main(String[] args) { long start = System.currentTimeMillis(); int re = 0; int[] sw = new int[]{0,3,6,7,8,10,16,18,44}; for (int i = 0;i<1000000;i++){ re = arrayInt(sw,i); System.out.println(re); } System.out.println(System.currentTimeMillis() - start+"毫秒");//12590 } public static int arrayInt(int[] sw,int z){ int i = z%10+1; if (i>7 || i<1){ return -1; }else { return sw[i]; } }

以上代码使用全新的思路,使用一个连续的数组代替了 switch 语句。因为对数据的随机访问是非常快的,至少好于 switch 的分支判断。通过实验,使用switch的语句耗时17860ms,使用数组的实现只耗时12590ms,提升了5s多。在软件开发中,换一种思路可能会取得更好的效果,比如使用数组替代switch语句就是就是一个很好的例子。

5、一维数组代替二维数组

由于数组的随机访问的性能非常好,许多JDK类库,如ArrayList、Vector等都是使用了数组作为其数组实现。但是,作为软件开发人员也必须知道,一位数组和二维数组的访问速度是不一样的。一位数组的访问速度要优于二维数组。因此,在性能敏感的系统中要使用二维数组的,可以尝试通过可靠地算法,将二维数组转为一维数组再进行处理,以提高系统的响应速度。

6、提取表达式

在软件开发过程中,程序员很容易有意无意让代码做一些“重复劳动”,在大部分情况下,由于计算机的告诉运行,这些“重复劳动”并不会对性能构成太大的威胁,但若将系统性能发挥到极致,提取这些“重复劳动”相当有意义。

来看下面的测试用例:

@Test public void test(){ long start = System.currentTimeMillis(); ArrayList list = new ArrayList(); for (int i = 0;i<100000;i++){ System.out.println(list.add(i)); } //以上是为了做准备 for (int i = 0;i<list.size();i++){ System.out.println(list.get(i)); } System.out.println(System.currentTimeMillis() - start);//5444 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfgzg.html