java:bestpracticejava

Les règles de programmation Java, les règles de présentation de code Java et les règles de nommage.

Présentation d’un fichier Java

Règles de programmation

L’erreur de frappe assez commune est l’utilisation de l’opérateur d’affectation = en lieu en place d’un test d’égalité ==.

En mettant une constante à gauche de l’opérateur, nous sommes sûrs qu’une anomalie sera détectée par le compilateur.

Aucune erreur ne sera générée par le compilateur sur le code suivant :

if (var = false) // erreur de frappe

par contre le compilateur en détectera une si on remplace par :

if (false = var)

Il peut s’agir d’une erreur de frappe du programmeur, sinon il faut renoncer aux affectations dans une condition ‘if’.

Exemple :

if (myBool = myClass.isValid (myIdent)) { // Incorrect
…
myBool = myClass.isValid (myIdent);
if (myBool) { // Affectation correcteif (myBool == myClass.isValid (myIdent)) { // Test correct

Grouper les membres selon leur visibilité et leur nature :

  • visibilité : les membres publics d’abord,
  • nature : variables d’instance ou de classe, constante, constructeurs, méthode d’instance ou de classe, …)
class Foo {
  private int privateThing () { // Incorrect
  }
  int publicMethod () {
  }
}
 
class FooNew {
  int publicMethod () {
  }
  private int privateThing () {  // Correct
  }
}

Il est d’usage de cacher des variables d’instance de classe. En contrepartie, offrez la possibilité de récupérer ces données par des méthodes d’accès à ces données.

class Foo{
   int _age = 5; // devrait être private
   private int _note = 18 ; // Correct
   final public int getNote () {
      return _note ;
   }
}

Ceci rend obscur le lien entre existant entre la classe parente et la classe fille.

public class Foo{
   protected int x = 10;
}
 
//à remplacer par :
public class Foo_ extends Foo{
   protected int x = 100; // Surcharge interdite.
}

Ne pas surcharger une méthode définie “private” dans la classe mère. Cela peut rendre confus l'usage de la classe.

class Foo extends Super {
    private void method () {}  // VIOLATION
}
 
class Super {
  private void method () {}
 
  public static void main (String[] args) {
    Foo x = new Foo ();
    test (x);
  }
 
  private static void test (Super x) {
    // appelle 'Super.method ()', et pas 'Foo.method ()'
    x.method ();
  }  
}
 
//corriger de façon à déclarer une méthode private nommée différemment :
class FooFixed extends Super {
    private void renamedMethod () {} // nom différent, correct
}

Standard de codage

Dans les interfaces, les méthodes sont toujours “public” et “abstract”. Les champs des interfaces sont toujours “public”, “static” et “final”.

Exemple faux :

interface Foo {
    public void method ();  // Inutile
    abstract int getSize ();  // Inutile
    static int SIZE = 100;  // Inutile
}

Exemple correct :

interface FooFixed {
    void method ();
    int getSize ();
    int SIZE = 100;
}

Il peut s'agir d'une déclaration de variable pour laquelle le code a été supprimé, mais la suppression de la déclaration a été oubliée.

Tous les variables statiques doivent être initialisées.

Les autres types de variables qui ne sont pas des attributs de classe doivent également être initialisés.

Les variables doivent être déclarées avec une portée aussi limitée que possible.

Déclarer plusieurs variables sur la même ligne peut diminuer la clarté du code.

Une déclaration par ligne peut inciter à commenter chaque déclaration.

Imbriquer une affectation à l’intérieur d’une autre affectation peut rendre le code difficile à lire. Il est préférable de procéder en plusieurs étapes : une affectation par ligne.

public class Foo {
    int method (int i, int j) {
        int k = (i = i + j) + j;  // Double affectation
        return k;
    }
}
//à remplacer par :
public class FooFixed {
    int method (int i, int j) {
        i = i + j;  // Premier temps
        int k = i + j;  // Deuxième temps
        return k;
    }
 
}

Copier une constante chaîne de caractères dans un Objet String est une perte de temps et est redondant. Déclarer la chaîne comme constante chaîne de caractères.

class Foo {
    void method () {
        System.out.println (_s);
    }
    private String _s = new String ("foo");  // Non correct
}
 
//à remplacer par :
class FooFixed {
    void method () {
        System.out.println (_s);
    }
    private static final String _s = "foo";  // Correct
}

Imbriquer plusieurs instructions sur une seule ligne peut rendre le code difficile à lire

int simple, tableau[]; // confusion possible
 
//à découper en deux déclarations :
int simple;
int tableau[];

Il est préférable d’utiliser des méthodes abstraites dans les classes de base plutôt que des méthodes sans code ou avec un code jamais utilisé.

Attention : Seule une classe abstract peut définir une méthode abstract.

Java est un langage de programmation très typé. Les conversions de type doivent être faites de façon explicite.

final short origine;
int destination;
destination = origine; // Non correct : converti implicitement
destination = (int)origine; // Correct : conversion explicite

Le 'l' minuscule peut être compris comme un '1' par le lecteur.

private final long _c1 = 12345L;
private final long _c2 = 12345l;

Déclencher une exception dans un bloc “catch” casse la pile des exceptions. On ne peut plus connaître l'exception d'origine.

Conventions de nommage

Les noms des packages doivent être libellés en caractères minuscules.

Ceci ayant pour but de ne pas faire de confusions éventuelles avec les noms des classes ou de constantes.

package FOO // incorrect
public class MaClasse {
}
 
//à remplacer par :
package foo // correct
public class MaClasse {
}

Les noms des classes doivent commencer par une lettre majuscule.

public class Test {
}

Les noms des interfaces doivent commencer par une lettre majuscule, chaque mot devant être Capitalized.

public interface TestInterface {
}

L’identificateur d’une classe ou d’une interface doit être un nom ou un groupe nominal suffisamment descriptif. De plus, la première lettre de chaque champ sémantique le composant doit être en majuscule, et le reste en minuscules.

Pour les interfaces, le nom peut être aussi un adjectif caractérisant le comportement attendu d’une implémentation de cette interface. Dans le cas où l’interface ne correspond pas à un comportement mais à un ensemble de services rendu par un objet (métier), le nom de l’objet est préfixé par I (exemple : INoeud)

Le nom d’une classe d’exception se termine par Exception.

Le nom d’une classe se termine par Impl s’il existe une interface du même nom. (exemple : NoeudImpl implémente les méthodes définies dans INoeud)

Le nom d’une méthode doit commencer par une minuscule et peut être composé de plusieurs mots dont le premier est un verbe

Les méthodes d’affectation d’un attribut (les mutateurs) s’appellent setAttribut

Les méthodes de récupération d’un attribut s’appellent getAttribut.

Les méthodes de récupération d’une longueur sont préfixées length.

public boolean isOk () {
   return this.ok ;
}

Les méthodes d’un objet Origine permettant de le convertir en un autre objet Destination doit être nommé toDestination.

Le nom d’un attribut (sauf pour les constantes) est une suite de mots collés dont le premier est en minuscule et les suivants sont Capitalized (première lettre en majuscule). Un blanc souligné ‘_’ est ajouté à la fin du nom de l’attribut de manière à pouvoir différentier facilement attribut de variables locales dans une méthode.

Le nom d’une constante doit être intégralement en majuscules. Si le nom de la constante comporte plusieurs mots, ils doivent être séparés par le caractère souligné (‘_’).

Les variables locales et les paramètres de méthodes sont identifiés par des noms courts, significatifs et généralement en minuscules (*) Les paramètres de méthode sont de plus préfixés par la lettre ‘p’. (exemple : pnoeud). Remarque : Les noms de variables ne sont pas à préfixer pour indiquer leur type/origine.

Les noms d’un seul caractère sont à éviter, sauf pour les variables de boucle (i, j, k) et les exceptions (e).

(*) Une variable peut avoir plusieurs mots dans son nom ; dans ce cas-là il convient d’appliquer la règle sur le nommage des attributs

Dans la mesure du possible, utiliser une seule langue pour nommer les noms de fichiers, les noms de classes, d’interfaces, de méthodes, d’attributs ou de variables.

Portabilité

Utilisez les constantes de classes standard si vous avez à tester les limites. Ne pas utiliser de constante “littérales” (telles que 123 ou 3.141592, …) sans avoir vérifié que la limite existe dans la classe sous forme de constante “final”. Remarque : Les « valeurs magiques » sont proscrites. Tous les objets/valeurs constants sont à reporter dans des variables statiques de la classe où ils sont utilisés. Ne pas redéfinir de objets/valeurs constants dans 2 classes différents s’il s’agit du même objet/valeur.

//Utilisation des constantes 
java.lang.Integer.MAX_VALUE;
java.lang.Double.NEGATIVE_INFINITY;

Utiliser 'System.getProperty ()' et les méthodes correspondantes 'getTypeName ()' des types “boolean”, “integer”, et “long”. Ceci permet de récupérer les propriétés système de Java plutôt que des variables d'environnement.

public class ENV {
  void method (String name) {
    System.getProperty (name);  // au lieu de System.getenv
  }
}

Optimisation

Les méthodes d’accès aux données private doivent être déclarées final. Ceci indique au compilateur que la méthode ne peut être surchargée, et qu’elle peut être utilisée « inline ».

Cela doit être utilisé avec prudence. En revanche, il n’y a pas de risque à l’appliquer à des méthodes private.

Pour écrire plus rapidement le code java, et pour avoir des lignes de code plus courtes, utiliser les opérateurs d’affectations abrégés, tels que +=, -=, *=, /=, »=, …

Certains compilateurs s’exécutent plus rapidement si le code est écrit ainsi.

Remarque : Privilégier, dans l’ordre :

  • vitesse d’exécution
  • lisibilité du code
  • vitesse de compilation

Par conséquent, n’éviter les instructions break et continue que si l’algorithme permet de le faire sans perte de performance. Attention : éviter tout test inutile dans une boucle et, à plus forte raison, toute création d’objet inutile.

A des fins d’optimisation, il faut sortir des boucles les invariants ou l’utilisation d’une méthode. En règle générale, il faut sortir tous les calculs indépendants de la boucle elle-même

Les “streams” utilisent des ressources et doivent être correctement fermés.

Ceci évite que la compatibilité de sérialisation entre les différentes versions de votre classe. Si vous ne spécifiez pas un UID de version, alors il sera automatiquement généré en se basant sur le contenu de la classe. Si l'UID change dans une nouvelle version de cotre classe, alors vous ne serez pas en mesure de supprimer la sérialisation d'une copie d'une ancienne version de votre classe, même si la forme “serialisée” n'a pas changé.

System.arraycopy() est plus rapide. System.arraycopy(array, 0, length, dest, 0, length);

Toute classe avec des attributs doit implémenter une méthode toString(). La String retournée doit avoir comme format : Classe@id[attribut1=valeur1,attribut2=valeur2,attribut3 …], org.apache.commons.lang.builder.ToStringBuilder est utilisé à cet effet, exemple:

public class Person {
   String name;
   int age;
   boolean isSmoker;
 
   //...
 
   public String toString() {
     return new ToStringBuilder(this).
       append("name", name).
       append("age", age).
       append("smoker", smoker).
       toString();
   }
 }

Une méthode ayant un nombre important de paramètres indique un accès complexe à l’objet. Évitez les méthodes avec plus de 5 paramètres.

Un fichier Java ne doit pas contenir plus de 2000 lignes (code & commentaires)

La rupture de séquence dans une boucle avec les instructions break et continue est déconseillé. L’usage de break n’est autorisé que dans un switch.

N’éviter les instructions break et continue que si l’algorithme permet de le faire sans perte de performance.

Ne pas entourer avec des parenthèses la valeur retournée par l’instruction ‘return’.

  • java/bestpracticejava.txt
  • Dernière modification: 2018/10/13 14:59
  • (modification externe)