Maison  >  Article  >  Java  >  Exemples d'optimisation des performances du programme en Java

Exemples d'optimisation des performances du programme en Java

黄舟
黄舟original
2017-07-27 10:31:571130parcourir

1. Évitez d'utiliser des expressions complexes dans les conditions de boucle

Sans optimisation de compilation, la condition de boucle sera répétée dans le calcul de la boucle, si vous n'utilisez pas expressions complexes et conservez la valeur de la condition de boucle inchangée, le programme s'exécutera plus rapidement.

Exemple :

import java.util.vector;
class cel {
    void method (vector vector) {
        for (int i = 0; i < vector.size (); i++)  // violation
            ; // ...
    }
}


Correction :

class cel_fixed {
    void method (vector vector) {
        int size = vector.size ()
        for (int i = 0; i < size; i++)
            ; // ...
    }
}



II , définissez la taille initiale des « vecteurs » et des « tables de hachage »

Lorsque jvm augmente la taille du vecteur, il doit recréer un tableau plus grand et copier le contenu du tableau d'origine . Enfin, le tableau d'origine est recyclé. On peut constater que l’expansion de la capacité vectorielle prend du temps.
Souvent, la taille par défaut de 10 éléments n'est pas suffisante. Vous feriez mieux de faire une estimation précise de la taille optimale dont vous avez besoin.

Exemple :

import java.util.vector;
public class dic {
    public void addobjects (object[] o) {
        // if length > 10, vector needs to expand
        for (int i = 0; i< o.length;i++) {    
            v.add(o);   // capacity before it can add more elements.
        }
    }
    public vector v = new vector();  // no initialcapacity.
}


Correction :
Définissez vous-même la taille initiale.

    public vector v = new vector(20);  
    public hashtable hash = new hashtable(10);

3. Fermez le flux dans le bloc final

Les ressources utilisées dans le programme doivent être libérées pour éviter Fuites de ressources. Il est préférable de le faire dans un bloc final. Quel que soit le résultat de l'exécution du programme, le bloc final sera toujours exécuté pour garantir que la ressource est correctement fermée.
 
Exemple :

import java.io.*;
public class cs {
    public static void main (string args[]) {
        cs cs = new cs ();
        cs.method ();
    }
    public void method () {
        try {
            fileinputstream fis = new fileinputstream ("cs.java");
            int count = 0;
            while (fis.read () != -1)
                count++;
            system.out.println (count);
            fis.close ();
        } catch (filenotfoundexception e1) {
        } catch (ioexception e2) {
        }
    }
}

Correction :
Ajouter un bloc final après la dernière capture

Utiliser le système '4. .arraycopy ()' au lieu de copier le tableau en boucle

'system.arraycopy ()' est beaucoup plus rapide que de copier le tableau en boucle.
 
Exemple :

public class irb
{
    void method () {
        int[] array1 = new int [100];
        for (int i = 0; i < array1.length; i++) {
            array1 [i] = i;
        }
        int[] array2 = new int [100];
        for (int i = 0; i < array2.length; i++) {
            array2 [i] = array1 [i];                 // violation
        }
    }
}


Correction :

public class irb
{
    void method () {
        int[] array1 = new int [100];
        for (int i = 0; i < array1.length; i++) {
            array1 [i] = i;
        }
        int[] array2 = new int [100];
        system.arraycopy(array1, 0, array2, 0, 100);
    }
}

5. Autoriser l'accès aux variables dans les méthodes Getter/setter d'instance deviennent "finales"

Les méthodes getter/setter simples doivent être rendues finales, ce qui indique au compilateur que cette méthode ne sera pas surchargée, donc, peuvent devenir "inline "

Exemple :

class maf {
    public void setsize (int size) {
         _size = size;
    }
    private int _size;
}

Correction :

class daf_fixed {
    final public void setsize (int size) {
         _size = size;
    }
    private int _size;
}


6, Évitez les instances d'opérations inutiles


Si le type statique de l'objet de gauche est égal à celui de droite, l'instance d'expression retournera toujours vrai.
 
Exemple : 

public class uiso {
    public uiso () {}
}
class dog extends uiso {
    void method (dog dog, uiso u) {
        dog d = dog;
        if (d instanceof uiso) // always true.
            system.out.println("dog is a uiso");
        uiso uiso = u;
        if (uiso instanceof object) // always true.
            system.out.println("uiso is an object");
    }
}

Correction : 
Supprimez l'instance d'opération inutile.
 

class dog extends uiso {
    void method () {
        dog d;
        system.out.println ("dog is an uiso");
        system.out.println ("uiso is an uiso");
    }
}

7. Évitez les opérations de style inutiles

Toutes les classes héritent directement ou indirectement de l'auto-objet. De même, toutes les sous-classes sont implicitement « égales » à leur classe parent. Ensuite, l’opération de modélisation de la sous-classe vers la classe parent est inutile.
Exemple :

class unc {
    string _id = "unc";
}
class dog extends unc {
    void method () {
        dog dog = new dog ();
        unc animal = (unc)dog;  // not necessary.
        object o = (object)dog;         // not necessary.
    }
}

Correction :     

class dog extends unc {
    void method () {
        dog dog = new dog();
        unc animal = dog;
        object o = dog;
    }
}

8. Si vous recherchez uniquement un seul caractère, utilisez charat() Au lieu de Startswith()

appeler Startswith() avec un caractère comme argument fonctionnera également très bien, mais du point de vue des performances, appeler l'API de chaîne est sans aucun doute faux ! >    
Exemple :

public class pcts {
    private void method(string s) {
        if (s.startswith("a")) { // violation
            // ...
        }
    }
}
Correction      

Remplacez 'startswith()' par 'charat()'.

9. Utiliser l'opération Shift pour remplacer l'opération 'a / b'

public class pcts {
    private void method(string s) {
        if (&#39;a&#39; == s.charat(0)) {
            // ...
        }
    }
}


"/" est une opération très "coûteuse". L'utilisation de l'opération Shift sera plus rapide. et plus efficace. Exemple :

Correction :


public class sp {
    public static final int num = 16;
    public void calculate(int a) {
        int p = a / 4;            // should be replaced with "a >> 2".
        int p2 = a / 8;         // should be replaced with "a >> 3".
        int temp = a / 3;
    }
}

Utiliser l'opération de décalage au lieu de 'a*. b'

public class sp {
    public static final int num = 16;
    public void calculate(int a) {
        int p = a >> 2;  
        int p2 = a >> 3;
        int temp = a / 3;       // 不能转换成位移操作
    }
}

Idem que ci-dessus. [i]Mais personnellement, je pense que cette méthode ne doit être utilisée que si elle se situe dans une très grande boucle, les performances sont très importantes et vous savez ce que vous faites. Sinon, il ne serait pas rentable de réduire la lisibilité du programme en raison de l'amélioration des performances. Exemple :


Correction :


public class smul {
    public void calculate(int a) {
        int mul = a * 4;            // should be replaced with "a << 2".
        int mul2 = 8 * a;         // should be replaced with "a << 3".
        int temp = a * 3;
    }
}

11. Lors de l'ajout de chaînes, utilisez ' à la place de " " si la chaîne ne comporte qu'un seul caractère

package opt;
public class smul {
    public void calculate(int a) {
        int mul = a << 2;  
        int mul2 = a << 3;
        int temp = a * 3;       // 不能转换
    }
}

Exemple :
Correction :
Remplacer une chaîne d'un caractère avec ' '

public class str {
    public void method(string s) {
        string string = s + &#39;d&#39;
        string = "abc" + &#39;d&#39;   
    }
}


十二、不要在循环中调用synchronized(同步)方法

方法的同步需要消耗相当大的资料,在一个循环中调用它绝对不是一个好主意。

例子:

import java.util.vector;
public class syn {
    public synchronized void method (object o) {
    }
    private void test () {
        for (int i = 0; i < vector.size(); i++) {
            method (vector.elementat(i));    // violation
        }
    }
    private vector vector = new vector (5, 5);
}

更正:
不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式:

import java.util.vector;
public class syn {
    public void method (object o) {
    }
private void test () {
    synchronized{//在一个同步块中执行非同步方法
            for (int i = 0; i < vector.size(); i++) {
                method (vector.elementat(i));   
            }
        }
    }
    private vector vector = new vector (5, 5);
}



十三、将try/catch块移出循环

把try/catch块放入循环体内,会极大的影响性能,如果编译jit被关闭或者你所使用的是一个不带jit的jvm,性能会将下降21%之多!
        
例子:        

import java.io.fileinputstream;
public class try {
    void method (fileinputstream fis) {
        for (int i = 0; i < size; i++) {
            try {                                      // violation
                _sum += fis.read();
            } catch (exception e) {}
        }
    }
    private int _sum;
}

更正:        
将try/catch块移出循环        

 void method (fileinputstream fis) {
        try {
            for (int i = 0; i < size; i++) {
                _sum += fis.read();
            }
        } catch (exception e) {}
    }

十四、对于boolean值,避免不必要的等式判断

将一个boolean值与一个true比较是一个恒等操作(直接返回该boolean变量的值). 移走对于boolean的不必要操作至少会带来2个好处:
1)代码执行的更快 (生成的字节码少了5个字节);
2)代码也会更加干净 。

例子:

public class ueq
{
    boolean method (string string) {
        return string.endswith ("a") == true;   // violation
    }
}

更正:

class ueq_fixed
{
    boolean method (string string) {
        return string.endswith ("a");
    }
}

十五、对于常量字符串,用'string' 代替 'stringbuffer'

常量字符串并不需要动态改变长度。
例子:

public class usc {
    string method () {
        stringbuffer s = new stringbuffer ("hello");
        string t = s + "world!";
        return t;
    }
}

更正:
把stringbuffer换成string,如果确定这个string不会再变的话,这将会减少运行开销提高性能。

十六、用'stringtokenizer' 代替 'indexof()' 和'substring()'

字符串的分析在很多应用中都是常见的。使用indexof()和substring()来分析字符串容易导致 stringindexoutofboundsexception。而使用stringtokenizer类来分析字符串则会容易一些,效率也会高一些。

例子:

public class ust {
    void parsestring(string string) {
        int index = 0;
        while ((index = string.indexof(".", index)) != -1) {
            system.out.println (string.substring(index, string.length()));
        }
    }
}

十七、使用条件操作符替代"if (cond) return; else return;" 结构

条件操作符更加的简捷
例子:

public class if {
    public int method(boolean isdone) {
        if (isdone) {
            return 0;
        } else {
            return 10;
        }
    }
}

更正:

public class if {
    public int method(boolean isdone) {
        return (isdone ? 0 : 10);
    }
}


十八、使用条件操作符代替"if (cond) a = b; else a = c;" 结构

例子:

public class ifas {
    void method(boolean istrue) {
        if (istrue) {
            _value = 0;
        } else {
            _value = 1;
        }
    }
    private int _value = 0;
}



更正:

public class ifas {
    void method(boolean istrue) {
        _value = (istrue ? 0 : 1);       // compact expression.
    }
    private int _value = 0;
}


十九、不要在循环体中实例化变量

在循环体中实例化临时变量将会增加内存消耗

例子:        

import java.util.vector;
public class loop {
    void method (vector v) {
        for (int i=0;i < v.size();i++) {
            object o = new object();
            o = v.elementat(i);
        }
    }
}


        
更正:        
在循环体外定义变量,并反复使用        

import java.util.vector;
public class loop {
    void method (vector v) {
        object o;
        for (int i=0;i<v.size();i++) {
            o = v.elementat(i);
        }
    }
}



二十、确定 stringbuffer的容量

stringbuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建stringbuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。

例子:        

public class rsbc {
    void method () {
        stringbuffer buffer = new stringbuffer(); // violation
        buffer.append ("hello");
    }
}

        
更正:        
为stringbuffer提供寝大小。        

public class rsbc {
    void method () {
        stringbuffer buffer = new stringbuffer(max);
        buffer.append ("hello");
    }
    private final int max = 100;
}


二十一、尽可能的使用栈变量

如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static? local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。
        
例子:

public class usv {
    void getsum (int[] values) {
        for (int i=0; i < value.length; i++) {
            _sum += value[i];           // violation.
        }
    }
    void getsum2 (int[] values) {
        for (int i=0; i < value.length; i++) {
            _staticsum += value[i];
        }
    }
    private int _sum;
    private static int _staticsum;
}


        
更正:        
如果可能,请使用局部变量作为你经常访问的变量。
你可以按下面的方法来修改getsum()方法:        

void getsum (int[] values) {
    int sum = _sum;  // temporary local variable.
    for (int i=0; i < value.length; i++) {
        sum += value[i];
    }
    _sum = sum;
}


二十二、不要总是使用取反操作符(!)

取反操作符(!)降低程序的可读性,所以不要总是使用。

例子:

public class dun {
    boolean method (boolean a, boolean b) {
        if (!a)
            return !a;
        else
            return !b;
    }
}


更正:
如果可能不要使用取反操作符(!)

二十三、与一个接口 进行instanceof操作


基于接口的设计通常是件好事,因为它允许有不同的实现,而又保持灵活。只要可能,对一个对象进行instanceof操作,以判断它是否某一接口要比是否某一个类要快。

例子:

public class insof {
    private void method (object o) {
        if (o instanceof interfacebase) { }  // better
        if (o instanceof classbase) { }   // worse.
    }
}

class classbase {}
interface interfacebase {}


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn