Développons en Java
v 2.40   Copyright (C) 1999-2023 .   
105. Les motifs de conception (design patterns) 107. Les techniques de développement spécifiques à Java Imprimer Index Index avec sommaire Télécharger le PDF

 

106. Des normes de développement

 

chapitre    1 0 6

 

Niveau : niveau 2 Elémentaire 

 

Le but de ce chapitre est de proposer un ensemble de conventions et de règles pour faciliter la compréhension et donc la maintenance du code.

Ces règles ne sont pas à suivre explicitement à la lettre : elles sont uniquement présentées pour inciter les développeurs à définir et à utiliser des règles dans la réalisation du code surtout dans le cadre d'un travail en équipe. Les règles proposées sont celles couramment utilisées. Il n'existe cependant pas de règle absolue et chacun pourra utiliser tout ou partie des règles proposées.

La définition de conventions et de règles est importante pour plusieurs raisons :

Le contenu de ce document est largement inspiré par les conventions de codage historiquement proposées par Sun.

Ce chapitre contient plusieurs sections :

 

106.1. Les fichiers

Java utilise des fichiers pour stocker les sources et le bytecode des classes.

 

106.1.1. Les packages

Les packages permettent de grouper les classes sous une forme hiérarchisée. Le choix des critères de regroupement est laissé aux développeurs.

Il est préférable de regrouper les classes par packages selon des critères fonctionnels.

Les fichiers inclus dans un package doivent être insérer dans une arborescence de répertoires équivalente.

 

106.1.2. Les noms de fichiers

Chaque fichier source ne doit contenir qu'une seule classe ou interface publique. Le nom du fichier doit être identique au nom de cette classe ou interface publique en respectant la casse.

Il faut éviter d'utiliser dans ce nom des caractères accentués qui ne sont pas toujours utilisables par tous les systèmes d'exploitation.

Les fichiers sources ont pour extension .java car le compilateur javac fourni avec le J.D.K. utilise cette extension.

Exemple :
javac MaClasse.java

Les fichiers binaires contenant le bytecode ont pour extension .class car le compilateur génère un fichier avec cette extension à partir du fichier source .java correspondant. De plus, elle est obligatoire pour l'interpréteur Java qui l'ajoute automatiquement au nom du fichier fourni en paramètre.

Exemple :
java MaClasse

 

106.1.3. Le contenu des fichiers sources

Un fichier ne devrait pas contenir plus de 2 000 lignes de code.

Des interfaces ou classes privées ayant une relation avec la classe publique peuvent être rassemblées dans un même fichier. Dans ce cas, la classe publique doit être la première dans le fichier.

Chaque fichier source devrait contenir dans l'ordre :

  1. un commentaire concernant le fichier
  2. les clauses concernant la gestion des packages (la déclaration et les importations)
  3. les déclarations de classes ou de l'interface

 

106.1.4. Les commentaires de début de fichier

Chaque fichier source devrait commencer par un commentaire multiligne contenant au minimum des informations sur le nom de la classe, la version, la date, éventuellement le copyright et tous les autres commentaires utiles :

Exemple :
/*
 * Nom de classe : MaClasse
 *
 * Description   : description de la classe et de son rôle 
 *
 * Version       : 1.0
 *
 * Date          : 23/02/2001
 * 
 * Copyright     : moi
 */

 

106.1.5. Les clauses concernant les packages.

La première ligne de code du fichier devrait être une clause package indiquant à quel paquetage appartient la classe. Le fichier source doit obligatoirement être inclus dans une arborescence correspondante au nom du package.

Il faut indiquer ensuite l'ensemble des paquetages à importer : ceux dont les classes vont être utilisées dans le code.

Exemple :
package monpackage;

import java.util.*;
import java.text.*;

 

106.1.6. La déclaration des classes et des interfaces

Les différents éléments qui composent la définition de la classe ou de l'interface devraient être indiqués dans l'ordre suivant :

  1. les commentaires au format javadoc de la classe ou de l'interface
  2. la déclaration de la classe ou de l'interface
  3. les variables de classes (déclarées avec le mot clé static) triées par ordre d'accessibilité : d'abord les variables déclarées public, protected, package-private (sans modificateur d'accès) et enfin private
  4. les variables d'instances triées par ordre d'accessibilité : d'abord les variables déclarées public, protected, package friendly (sans modificateur d'accès) et enfin private
  5. le ou les constructeurs
  6. les méthodes : elles seront regroupées par fonctionnalités plutôt que selon leur accessibilité

 

106.2. La documentation du code

Il existe deux types de commentaires en Java :

Les commentaires ne doivent pas être entourés par de grands cadres dessinés avec des étoiles ou d'autres caractères.

Les commentaires ne devraient pas contenir de caractères spéciaux tels que le saut de page.

 

106.2.1. Les commentaires de documentation

Les commentaires de documentation utilisent une syntaxe particulière utilisée par l'outil javadoc pour produire une documentation standardisée des classes et interfaces au format HTML. La documentation de l'API du J.D.K. est le résultat de l'utilisation de cet outil de documentation

 

106.2.1.1. L'utilisation des commentaires de documentation

Cette documentation concerne les classes, les interfaces, les constructeurs, les méthodes et les champs.

La documentation est définie entre les caractères /** et */ selon le format suivant :

Exemple :
/**
 *  Description de la methode
 */
public void maMethode() {

La première ligne de commentaires ne doit contenir que /**

Les lignes de commentaires suivantes doivent obligatoirement commencer par un espace et une étoile. Toutes les premières étoiles doivent être alignées.

La dernière ligne de commentaires ne doit contenir que */ précédé d'un espace.

Un tel commentaire doit être défini pour chaque entité : une classe, une interface et chaque membre (variables et méthodes).

Javadoc définit un certain nombre de tags qu'il est possible d'utiliser pour apporter des précisions sur plusieurs informations.

Ces tags permettent de définir des caractéristiques normalisées. Il est possible d'inclure dans les commentaires des tags HTML de mise en forme (PRE, TT, EM ...) mais il n'est pas recommandé d'utiliser des tags HTML de structure tels que Hn, HR, TABLE ... qui sont utilisés par javadoc pour formater la documentation.

Il faut obligatoirement faire précéder l'entité documentée par son commentaire car l'outil associe la documentation à la déclaration de l'entité qui le suit.

 

106.2.1.2. Les commentaires pour une classe ou une interface

Pour les classes ou interfaces, javadoc définit les tags suivants : @see, @version et @author.

Exemple :
/**
 * description de la classe.
 * explication supplémentaire si nécessaire
 * 
 * @version 1.0
 *
 * @see UneAutreClasse
 * @author Jean Michel D.
 */

 

106.2.1.3. Les commentaires pour une méthode

Pour les méthodes, javadoc définit les tags suivants : @see, @param, @return, @exception et @author

Exemple :
/** 
 * description de la méthode.
 * explication supplémentaire si nécessaire 
 *  
 * @return      description de la valeur de retour 
 * @param       arg1 description du 1er argument 
 *    :           :         : 
 * @param       argN description du Neme argument 
 * @exception   Exception1  description de la première exception 
 *    :           :         : 
 * @exception ExceptionN  description de la Neme exception 
 * 
 * @see UneAutreClasse#UneAutreMethode 
 * @author   Jean Dupond 
 */

Remarques :

 

106.2.2. Les commentaires de traitements

Ces commentaires doivent ajouter du sens et des précisions au code : ils ne doivent pas reprendre ce que le code exprime mais expliquer clairement son rôle.

Tous les commentaires utiles à une meilleure compréhension du code et non inclus dans les commentaires de documentation seront insérés avec des commentaires de traitements. Il existe plusieurs styles de commentaires :

Il est conseillé de mettre un espace après le délimiteur de début de commentaires et avant le délimiteur de fin de commentaires lorsqu'il y en a un, afin d'améliorer sa lisibilité.

 

106.2.2.1. Les commentaires sur une ligne

Ces commentaires sont définis entre les caractères /* et */ sur une même ligne

Exemple :
if (i < 10) {
   /* commentaires utiles au code */
   ...
}

Ce type de commentaires doit être précédé d'une ligne blanche et doit suivre le niveau d'indentation courant.

 

106.2.2.2. Les commentaires sur une portion de ligne

Ce type de commentaires peut apparaître sur la ligne de code qu'elle commente mais il faut inclure un espace conséquent qui permette de séparer le code et le commentaire.

Exemple :
i++;                      /* commentaires utiles au code */

Si plusieurs lignes qui se suivent contiennent chacune un tel commentaire, il faut les aligner :

Exemple :
i++;                      /* commentaires utiles au code */
j++;                      /* second commentaires utiles au code */

 

106.2.2.3. Les commentaires multi-lignes

Exemple :
/*
 * Commentaires utiles au code
 */

Ce type de commentaires doit être précédé d'une ligne blanche et doit suivre le niveau d'indentation courant.

 

106.2.2.4. Les commentaires de fin de ligne

Ce type de commentaire peut délimiter un commentaire sur une ligne complète ou une fin de ligne.

Exemple :
i++;         // commentaires utiles au code

Ce type de commentaires peut apparaître sur la ligne de code qu'elle commente mais il faut inclure un espace conséquent qui permette de séparer le code et le commentaire.

Si plusieurs lignes qui se suivent contiennent chacune un tel commentaire, il faut les aligner :

Exemple :
i++;                      // commentaires utiles au code
j++;                      // second commentaires utiles au code

L'usage de cette forme de commentaires est fortement recommandé car il est possible d'inclure celui-ci dans un autre de la forme /* */ et ainsi mettre en commentaire un morceau de code incluant déjà des commentaires.

 

106.3. Les déclarations

 

106.3.1. La déclaration des variables

Il n'est pas recommandé d'utiliser des caractères accentués dans les identifiants de variables, cela peut éventuellement poser des problèmes dans le cas où le code est édité sur des systèmes d'exploitation qui ne les gèrent pas correctement.

Il ne doit y avoir qu'une seule déclaration d'entité par ligne.

Exemple :
String nom;
String prenom;

Cet exemple est préférable à

Exemple :
String nom, prenom;          //ce type de déclaration n'est pas recommandé

Il faut éviter de déclarer des variables de types différents sur la même ligne même si cela est accepté par le compilateur.

Exemple :
int age, notes[];            // ce type de déclaration est à éviter

Il est préférable d'aligner le type, l'identifiant de l'objet et les commentaires si plusieurs déclarations se suivent pour retrouver plus facilement les divers éléments.

Exemple :
String          nom          //nom de l'eleve
String          prenom       //prenom de l'eleve
int             notes[]      //notes de l'eleve

Il est fortement recommandé d'initialiser les variables au moment de leur déclaration.

Il est préférable de rassembler toutes les déclarations d'un bloc au début de ce bloc. (un bloc est un morceau de code entouré par des accolades).

La seule exception concerne la déclaration de la variable utilisée comme index dans une boucle.

Exemple :
for (int i = 0 ; i < 9 ; i++) { ... }

Il faut proscrire la déclaration d'une variable qui masque une variable définie dans un bloc parent afin de ne pas complexifier inutilement le code.

Exemple :
int taille;
...
void maMethode() {
    int taille;
}

 

106.3.2. La déclaration des classes et des méthodes

Il ne doit pas y avoir d'espaces entre le nom d'une méthode et sa parenthèse ouvrante.

L'accolade ouvrante qui définit le début du bloc de code doit être à la fin de la ligne de déclaration.

L'accolade fermante doit être sur une ligne séparée dont le niveau d'indentation correspond à celui de la déclaration.

Une exception tolérée concerne un bloc de code vide : dans ce cas les deux accolades peuvent être sur la même ligne.

La déclaration d'une méthode est précédée d'une ligne blanche.

Exemple :
class MaClasse extends MaClasseMere {
   String nom;
   String prenom;

   MaClasse(String nom, String prenom) {
      this.nom = nom;
      this.prenom = prenom;
   }

   void neRienFaire() {}
}

Il faut éviter d'écrire des méthodes longues et compliquées : le traitement réalisé par une méthode doit être simple et fonctionnel. Cela permet d'écrire des méthodes réutilisables dans la classe et facilite la maintenance. Cela permet aussi d'éviter la redondance de code.

Java propose deux syntaxes pour déclarer une méthode qui retourne un tableau : la première syntaxe est préférable.

Exemple :
public int[] notes() {     // utiliser cette forme 
public int notes()[] { 

Il est fortement recommandé de toujours initialiser les variables locales d'une méthode lors de leur déclaration car contrairement aux variables d'instances, elles ne sont pas implicitement initialisées avec une valeur par défaut selon leur type.

 

106.3.3. La déclaration des constructeurs

Elle suit les mêmes règles que celles utilisées pour les méthodes.

Il est préférable de définir explicitement le constructeur par défaut (le constructeur sans paramètre). Soit le constructeur par défaut est fourni par le compilateur et dans ce cas il serait préférable de le définir soit il existe d'autres constructeurs et dans ce cas le compilateur ne définit pas de constructeur par défaut.

Il est préférable de toujours initialiser les variables d'instance dans un constructeur soit avec les valeurs fournies en paramètres du constructeur soit avec des valeurs par défaut.

Exemple :
class Personne { 
   String nom; 
   String prenom; 
   int    age; 

   Personne() { 
      this( "Inconnu", "inconnu", -1 ); 
   } 

   Personne( String nom, String prenom, int age ) { 
      this.name    = nom; 
      this.address = prenom; 
      this.age     = age; 
   } 
}

Il est possible d'appeler un constructeur dans un autre constructeur pour faciliter l'écriture.

Il est recommandé de toujours appeler explicitement le constructeur hérité lors de la redéfinition d'un constructeur dans une classe fille grâce à l'utilisation du mot clé super.

Exemple :
class Employe extends Personne {

   int matricule;

   Employee() {
      super();
      matricule = -1;
   }
 
   Employee(String nom, String prenom, int age, int matricule) {
      super(nom, prenom, age);
      this.matricule = matricule;
   }
}

Il est conseillé de ne mettre que du code d'initialisation des variables d'instances dans un constructeur et de mettre les traitements dans des méthodes qui seront appelées après la création de l'objet.

 

106.3.4. Les conventions de nommage des entités

Les conventions de nommage des entités permettent de rendre les programmes plus lisibles et plus faciles à comprendre. Ces conventions permettent notamment de déterminer rapidement quelle entité désigne un identifiant, une classe ou une méthode.

Entités Règles Exemple
Les packages Toujours écrits tout en minuscules (norme Java 1.2) com.entreprise.projet
Les classes, les interfaces et les constructeurs

La première lettre est en majuscule.
Si le nom est composé de plusieurs mots, la première lettre de chaque mot doit être en majuscule, ne pas mettre de caractère underscore '_'
Le nom d'une classe peut finir par Impl pour la distinguer d'une interface qu'elle implémente.
Les classes qui définissent des exceptions doivent finir par Exception.

MaClasse
MonInterface
MaClasse()
Les méthodes

Leur nom devrait contenir un verbe.
La première lettre est obligatoirement une minuscule.
Si le nom est composé de plusieurs mots, la première lettre de chaque mot doit être en majuscule sans mettre de caractère underscore '_'
Les méthodes pour obtenir la valeur d'un champ doivent commencer par get suivi du nom du champ.
Les méthodes pour mettre à jour la valeur d'un champ doivent commencer par set suivi du nom du champ
Les méthodes pour créer des objets (factory) devraient commencer par new ou create
Les méthodes de conversion devraient commencer par to suivi par le nom de la classe renvoyée à la suite de la conversion

public float calculerMontant() {
Les variables

La première lettre est obligatoirement une minuscule et ne devrait pas être un caractère dollar '$' ou underscore '_' même si ceux-ci sont autorisés.
Pour les variables d'instances non publiques, certains recommandent de commencer par un underscore pour éviter la confusion avec le nom d'une variable fournie en paramètre d'une méthode telle que le setter.

Si le nom est composé de plusieurs mots, la première lettre de chaque mot doit être en majuscule, ne pas mettre de caractère underscore '_'.

Les noms de variables composés d'un seul caractère doivent être évités sauf pour des variables provisoires (index d'une boucle).
Les noms communs pour ces variables provisoires sont i, j, k, m et n pour les entiers et c, d et e pour les caractères.

String nomPersonne;
Date dateDeNaissance;
int i;
Les constantes

Toujours en majuscules, chaque mots est séparés par un underscore '_'. Ces variables doivent obligatoirement être initialisées lors de leur déclaration.

static final int VAL_MIN = 0;
static final int VAL_MAX = 9;

 

106.4. Les séparateurs

L'usage des séparateurs tels que les retours à la ligne, les lignes blanches, les espaces, etc ... permet de rendre le code moins « dense » et donc plus lisibles.

 

106.4.1. L'indentation

L'unité d'indentation est constituée de 4 espaces. Il n'est pas recommandé d'utiliser les tabulations pour l'indentation.

Il est préférable d'éviter les lignes contenant plus de 80 caractères.

 

106.4.2. Les lignes blanches

Elles permettent de définir des sections dans le code pour effectuer des séparations logiques.

Deux lignes blanches devraient toujours séparer deux sections d'un fichier source et les définitions des classes et des interfaces.

Une ligne blanche devrait toujours être utilisée dans les cas suivants :

 

106.4.3. Les espaces

Un espace vide devrait toujours être utilisé dans les cas suivants :

Il ne faut pas mettre d'espace entre un nom de méthode et sa parenthèse ouvrante.

Il ne faut pas non plus mettre de blanc avant les opérateurs unaires tels que les opérateurs d'incrément '++' et de décrément '--'.

Exemple :
i++;

 

106.4.4. La coupure de lignes

Il arrive parfois qu'une ligne de code soit très longue (supérieure à 80 caractères).

Dans ce cas, il est recommandé de couper cette ligne en une ou plusieurs en respectant quelques règles :

Exemple :
  maMethode(parametre1, parametre2, parametre3,
	    parametre4, parametre5);

 

106.5. Les traitements

Même s'il est possible de mettre plusieurs traitements sur une ligne, chaque ligne ne devrait contenir qu'un seul traitement :

Exemple :
i = getSize();
i++;

 

106.5.1. Les instructions composées

Elles correspondent à des instructions qui utilisent des blocs de code.

Les instructions incluses dans ce bloc sont encadrées par des accolades et doivent être indentées.
L'accolade ouvrante doit se situer à la fin de la ligne qui contient l'instruction composée.
L'accolade fermante doit être sur une ligne séparée au même niveau d'indentation que l'instruction composée.

Un bloc de code doit être définit pour chaque traitement même si le traitement ne contient qu'une seule instruction. Cela facilite l'ajout d'instructions et évite des erreurs de programmation.

 

106.5.2. L'instruction return

Elle ne devrait pas utiliser de parenthèses sauf si celles-ci facilitent la compréhension.

Exemple :
  return;
  return valeur;
  return (isHomme() ? 'M' : 'F'); 

 

106.5.3. L'instruction if

Elle devrait avoir une des formes suivantes :

Exemple :
  if (condition) {
     traitements;
  }
  
  if (condition) {
     traitements;
  } else {
     traitements; 
  }
  
  if (condition) {
     traitements;
  } else if (condition) {
     traitements;
  } else {
     traitements;
  }

Même si cette forme est syntaxiquement correcte, il est préférable de ne pas utiliser l'instruction if sans accolades :

Exemple :
    if (i == 10) i = 0;  // cette forme ne doit pas être utilisée

 

106.5.4. L'instruction for

Elle devrait avoir la forme suivante :

Exemple :
for ( initialisation; condition; mise à jour) {
     traitements;
}

 

106.5.5. L'instruction while

Elle devrait avoir la forme suivante :

Exemple :
while (condition) {
     traitements;
}

 

106.5.6. L'instruction do-while

Elle devrait avoir la forme suivante :

Exemple :
  do {
     traitements;
  } while ( condition);

 

106.5.7. L'instruction switch

Elle devrait avoir la forme suivante :

Exemple :

  switch (condition) {
  case ABC:
     traitements;
     break;
  case DEF:
     traitements;
     break;
  case XYZ:
     traitements;
     break;
  default:
     traitements;
     break;
  }

Il est préférable de terminer les traitements de chaque cas avec une instruction break et de l'enlever au besoin plutôt que d'oublier une instruction break nécessaire.

Toutes les instructions switch devrait avoir un cas 'default' en fin d'instruction : le traitement de tous les cas est une bonne pratique de programmation.

Même si elle est redondante, une instruction break devrait être incluse en fin des traitements du cas 'default' afin de généraliser la première recommandation.

 

106.5.8. Les instructions try-catch

Elle devrait avoir la forme suivante :

Exemple :
  try {
     traitements;
  } catch (Exception1 e1) {
     traitements;
  } catch (Exception2 e2) {
     traitements;
  } finally {
     traitements;
  }

 

106.6. Les règles de programmation

 

106.6.1. Le respect des règles d'encapsulation

Il ne faut pas déclarer de variables d'instances ou de classes publiques sans raison valable.

Il est préférable de restreindre l'accès à la variable avec un modificateur d'accès protected ou private et de déclarer des méthodes respectant les conventions instaurées dans les javaBeans : getXxx() ou isXxx() pour obtenir la valeur et setXxx() pour mettre à jour la valeur.

La création de méthodes sur des variables private ou protected permet d'assurer une protection lors de l'accès à la variable (déclaration des méthodes d'accès synchronized) et éventuellement un contrôle lors de la mise à jour de la valeur.

 

106.6.2. Les références aux variables et méthodes de classes.

Il n'est pas recommandé d'utiliser des variables ou des méthodes de classes à partir d'un objet instancié : il ne faut pas utiliser objet.methode() mais classe.methode().

Exemple à ne pas utiliser si afficher() est une méthode de classe :
MaClasse maClasse = new MaClasse();
maClasse.afficher();

Exemple à utiliser si afficher() est une méthode de classe :
MaClasse.afficher();

 

106.6.3. Les constantes

Il est préférable de ne pas utiliser des constantes numériques codées en dur dans le code mais de déclarer des constantes avec des noms explicites. Une exception concerne les valeurs -1, 0 et 1 dans les boucles for.

 

106.6.4. L'assignement des variables

Il n'est pas recommandé d'assigner la même valeur à plusieurs variables sur la même ligne :

Exemple :
i = j = k;                 //cette forme n'est pas recommandée

Il ne faut pas utiliser l'opérateur d'assignement imbriqué.

Exemple à proscrire :
  valeur = (i = j + k ) + m;

Exemple :
  i = j + k;
  valeur = i + m;

Il n'est pas recommandé d'utiliser l'opérateur d'assignation = dans une instruction if ou while afin d'éviter toute confusion.

 

106.6.5. L'usage des parenthèses

Il est préférable d'utiliser les parenthèses lors de l'usage de plusieurs opérateurs pour éviter des problèmes liés à la priorité des opérateurs.

Exemple :
  if (i == j && m == n)                // à éviter
  if ( (i == j) && (m == n ))          // à utiliser

 

106.6.6. La valeur de retour

Il est préférable de minimiser le nombre d'instructions return dans un bloc de code.

Exemple à eviter :
  if (isValide()){
     return true;
  } else {
    return false;
  }

Exemple :
  return isValide();

Exemple :
  if (isValide()) {
     return x;
  } else return y;

Exemple à utiliser :
  return (isValide() ? x : y)

 

106.6.7. La codification de la condition dans l'opérateur ternaire ? :

Si la condition dans un opérateur ternaire ? : contient un opérateur binaire, cette condition doit être mise entre parenthèses.

Exemple :
  ( i >= 0 ) ? i : -i;

 

106.6.8. La déclaration d'un tableau

Java permet de déclarer les tableaux de deux façons :

Exemple :
  public int[] tableau = new int[10];
  public int tableau[] = new int[10]; 

L'usage de la première forme est recommandé.

 


105. Les motifs de conception (design patterns) 107. Les techniques de développement spécifiques à Java Imprimer Index Index avec sommaire Télécharger le PDF    
Développons en Java
v 2.40   Copyright (C) 1999-2023 .