Revue de code II

Suite de la revue de code : BigDecimal, nommage et concaténation de String.

BigDecimal.equals vs BigDecimal.compareTo

Deux BigDecimaux qui ont la même valeur avec une précision différente ne sont pas considérés comme égaux à l’aide la méthode equals. En revanche, ils sont considérés comme égaux si on les compare avec la méthode compareTo.

Exemple :

BigDecimal bigDecimal1 = new BigDecimal(0);//0
BigDecimal bigDecimal2 = BigDecimal.ZERO;//0
BigDecimal bigDecimal3 = BigDecimal.valueOf(0.0);//0.0

System.out.println(bigDecimal1.equals(bigDecimal2));  //true
System.out.println(bigDecimal1.equals(bigDecimal3));  //false
System.out.println(bigDecimal2.equals(bigDecimal3)); //false

System.out.println(bigDecimal1.compareTo(bigDecimal2)==0); //true
System.out.println(bigDecimal1.compareTo(bigDecimal3)==0); //true
System.out.println(bigDecimal2.compareTo(bigDecimal3)==0); //true

public int compareTo(BigDecimal val)

Compares this BigDecimal with the specified BigDecimal. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. This method is provided in preference to individual methods for each of the six boolean comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for performing these comparisons is: (x.compareTo(y) <op> 0), where <op> is one of the six comparison operators.

public abstract

Dans un autre registre, quelque chose qui revient souvent dans le code :

Les termes public ou abstract dans la déclaration des méthodes d’une interface.  L’ensemble des méthodes d’une interface sont obligatoirement public abstract, inutile donc de l’ajouter.

Mauvais nommage

Il y a toujours des variables mal nommées.  Plusieurs raisons à cela :

  • elles ne respectent pas les règles de nommage Java (variables en majuscule alors que non final static, présence de _ dans une variable local).
  • le nom de la variable ne dépend de ce qu’elle fait : autant i,j,k sont des noms de variables admettables pour des compteurs au sein de boucle, pas ailleurs.
  • le nom de la variable n’est pas compréhensible : updateFMTTTL si FMTTTL ne renvoie à rien fonctionnellement parlant,  il faut lui donner un autre nom. Il vaut mieux une variable à nom long mais compréhensible plutôt qu’essayer de faire court. Ceux qui vous passeront derrière vous en remercieront !

Le livre Coder Proprement de Robert C Martin consacre plusieurs pages intéressantes sur ce sujet.

La concaténation de String

Exemple 1 : Avec utilisation de l’opérateur +

long start = System.currentTimeMillis();
String a = " Concaténation";
for (int i = 0; i < 10000; i++) {
a += i;
}
System.out.println(a);
System.out
.println(" in " + (System.currentTimeMillis() - start) + "ms");

Exemple 2 : Avec un StringBuilder

start = System.currentTimeMillis();
StringBuilder stringBuffer = new StringBuilder (" Concaténation");
for (int i = 0; i < 10000; i++) {
stringBuffer.append(i);
}
System.out.println(stringBuffer.toString());
System.out
.println(" in " + (System.currentTimeMillis() - start) + "ms");

Durée des 10000 concaténations :

Exemple 1 : 360ms

Exemple 2 : 15ms

Il a néanmoins des cas où il est préférable d’utiliser la concaténation de string (+ ou String.concat) :

pour aérer une ligne ex :

String myString = " line 1 "
                     +  "line 2";

pour strictement moins de 4 concaténation :

 logger.debug("x :"+x+"y :"+y);

Le compilateur transforme automatiquement cettte ligne en utilisant un StringBuilder System.out.println((new StringBuilder()).append(« x: »).append(x).append( » y: »).append(y).toString());

Les tests avec les objets StringBuilder et StringBuffer renvoient des résultats quasiment similaires. StringBuilder étant un tout petit plus rapide, il est à utiliser le plus souvent possible. Le StringBuffer est quand à lui thread-safe donc à utiliser dans les environnements concurrents.

Il n’est pas forcément judicieux de remplacer toutes les concaténations de string automatiquement par un StringBuilder / StringBuffer. Si elles sont dans une boucle, le gain peut être remarquable dans les autres cas, cela se discute.  Les StringBuilder / StringBuffer alourdissent considérablement la syntaxe et le gain est parfois très faible. Comme dans la plupart des cas, l’optimisation prématurée est à éviter !  Pour appronfondir le sujet, voir l’interview du Dr Heintz Kabutz : http://java.sun.com/developer/technicalArticles/Interviews/community/kabutz_qa.html

2 Responses to “Revue de code II”

  1. Piwaï dit :

    Sympa ce petit article ! A propos de « Les StringBuilder / StringBuffer alourdissent considérablement la syntaxe », je trouve que celle-ci se trouve grandement améliorée quand on y ajoute des retours à la ligne, avec « // » pour que l’IDE ne reformate pas automatiquement :

    StringBuilder sb = new StringBuilder();

    sb //
    .append(« une ») //
    .append(« concaténation ») //
    .append(2) //
    .append(« txt »);

    my 2 cents :)

  2. Eligriv dit :

    Il est intéressant de préciser que la concaténation de deux literals avec un ‘+’ est résolue à la compilation (et non au runtime donc). C’est pour ça qu’il ne faut pas utiliser de stringbuilder dans ce cas.

    Pour les interfaces, ajouter un public n’est pas toujours superflu, car même si on sait qu’une méthode d’interface est publique systématiquement, ça évite la confusion avec les default (package).

    Enfin, merci pour le truc sur les BigDecimal ! C’est effrayant de voir toutes les erreurs qui pourraient être provoquées par cet equals() ..

Leave a Reply