zoukankan      html  css  js  c++  java
  • 有助于改善性能的技巧

    1. 慎用异常

      在Java软件开发中,经常会使用try-catch进行错误捕获,但是,try-catch语句对系统性能而言是非常糟糕的。因此,应尽量避免将其应用在循环当中。

    2. 使用局部变量

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

    3. 位运算代替乘除法

      在所有的运算中,位运算是最为高效的。因此,可以尝试使用位运算代替部分算术运算,来提高系统的运算速度。最典型的就是对于整数的乘除法运算优化。

    4. 替换switch

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

      来看下面的例子:

            int re = 0;
            for(int i=0;i<10000000;i++){
                re = switchInt(i);
            }
            protected 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,实现相同的程序功能,那么性能就能有很大的提升空间。以下代码实现了与上例switch语句相同的功能:

            int re = 0;
            int[] sw = new int[]{0, 3, 6, 7, 8, 10, 16, 18, 44}; //替代switch逻辑
            for(int i=0;i<10000000;i++){
                re = arrayInt(sw, i);
            }
            protected int arrayInt(int[] sw, int z){
                int i = z%10 + 1;
                if(i<1||i>8)    //模拟switch的default
                    return -1;
                else
                    return sw[i];
            }

      以上代码采用全新的思路,使用一个连续的数组代替了switch语句。因为对数组的随机访问时非常快的,至少好于switch的分值判断,因此它的速度一定会快于原来的实现。通过实验,使用switch的语句相对耗时80ms,而使用数组的实现只相对耗时62ms。

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

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

    6. 提取表达式

       在软件开发过程中,程序员很容易有意无意地让代码做一些“重复劳动”,在大部分情况下,由于计算机的高速运行,这些“重复劳动”并不会对性能构成太大的威胁,但若希望将系统性能发挥到极致,提取这些“重复劳动”相当有意义。尽可能让程序少做重复计算,尤其要关注在循环体内的代码,从循环体内提取重复的代码可以有效地提升系统性能。

    7. 展开循环

       与前面所介绍的优化技巧略有不同,展开循环是一种在极端情况下使用的优化手段,因为展开循环很可能会影响代码的可读性和可维护性,而这两者对软件系统来说也是极为重要的。但是,当性能问题成为系统的主要矛盾时,展开循环绝对是一种值得尝试的技术。

    一个普通的循环代码如下所示:

         int[] array = new int[9999999];
            for(int i=0;i<9999999;i++){
                array[i] = i;
            }

    展开循环后,类似以下格式:

            int[] array = new int[9999999];
            for(int i=0;i<9999999;i += 3){
                array[i] = i;
                array[i+1] = i+1;
                array[i+2] = i+2;
            }

      以上两段代码功能完全相同,但第二段代码进行了循环展开的优化,在一个循环体内处理了原代码段中的3个循环逻辑。运行以上两段代码,第一段代码相对耗时94ms,第二段代码相对耗时31ms,可见展开循环后,减少循环次数,对提升系统性能很有帮助。

    8. 布尔运算代替位运算

       虽然位运算的速度远远高于算术运算,但是在条件判断时,使用位运算替代布尔运算却是非常错误的选择。因为在条件判断时,Java会对布尔运算做相当充分的优化。在布尔表达式的计算中,只要表达式的值可以确定,就会立即返回,而跳过剩余子表达式的计算。若使用位运算(按位与、按位或)代替逻辑与和逻辑或,虽然位运算本身性能没有问题,但是位运算总是要将所有的子表达式全部计算完成后,再给出最终结果。因此,从这个角度说,使用位运算替代布尔运算会使系统进行很多无用计算。

    9. 使用arraycopy()

      数组复制是一项使用频率很高的功能,JDK中提供了一个高效的API来实现它:

    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

      System.arraycopy()函数是native函数,通常native函数的性能要优于普通函数,仅出于性能考虑,在软件开发时,应尽可能调用native函数。

    10. 使用Buffer进行I/O操作

      除NIO外,使用java进行I/O操作有两种基本方式:

    1. 使用基于InputStream和OutputStream的方式
    2. 使用Writer和Reader

      无论使用哪种方式进行文件的I/O,如果能合理地使用缓冲,就能有效地提高I/O的性能。

     11. 使用clone()代替new

      在Java中新建对象实例最常用的方法是使用new关键字。JDK对new关键字的支持非常好,使用new关键字创建轻量级对象时,速度非常快。但是,对于重量级对象,由于对象在构造函数中可能会进行一些复杂而且耗时的操作,因此,构造函数的执行时间可能会比较长。这就导致了创建对象的耗时很长,同时也使得系统无法在短期内获得大量的实例。为了解决这个问题,可以使用Object.clone()方法。

      Object.clone()方法可以绕过对象构造函数,快速复制一个对象实例。由于不需要调用对象构造函数,因此,clone()方法不会受到构造函数性能的影响,能够快速生成一个实例。但是,在默认的情况下,clone()方法生成的实例只是原对象的浅拷贝。如果需要深拷贝,则需要重新实现clone()方法。

     12. 静态方法替代实例方法

      使用关键字static声明的方法为静态方法。在Java中,由于实例方法需要维护一张类似虚函数表的结构,以实现对多态的支持。与静态方法相比,实例方法的调用需要更多的资源。因此,对于一些常用的工具类方法,没有对其进行重载的必要,那么就可以将它们声明为static,便可以加速方法的调用。对于一些工具类,应该使用static方法实现,这样不仅可以加速函数调用的速度,同时,调用static方法也不需要生成类的实例,比调用实例方法更为方便、易用。

  • 相关阅读:
    VirtualBox中的Linux读取Windows共享目录
    Windows10资源管理器去掉左侧“下载、文档、图片、音乐、视频”等目录
    在Eclipse ee中成功使用jQuery UI插件
    (medium)LeetCode .Implement Trie (Prefix Tree)
    (*medium)LeetCode 211.Add and Search Word
    (easy)LeetCode 257.Binary Tree Paths
    2016 360笔试 编程题 2
    2016 360笔试 编程题1
    (番外)使用DFS和BFS实现拓扑排序
    (medium)LeetCode 210.Course Schedule II
  • 原文地址:https://www.cnblogs.com/gaopeng527/p/4904474.html
Copyright © 2011-2022 走看看