Partage
  • Partager sur Facebook
  • Partager sur Twitter

Conventions de codage en Java

Quelques manières pour "mieux" coder

14 avril 2009 à 0:08:38

S.v.p ne postez rien dans ce topic sinon il n'y a aucune chance qu'il soit mis en post-it. Pour faire des modifications / ajouts / suppression MPez moi.

Salut à tous,

Introduction


Ce topic à pour but d'informer tout le monde concernant les conventions de codage à mettre en pratique pour le Java. Bon tout d'abord à quoi ça sert une convention de codage? Eh ben c'est pour que tout le monde code de la même manière plus ou moins et comme ça quand on reprend le code de quelqu'un on ne se perd pas complétement. Voilà trois raisons principales :
  • 80% de la vie d'une application c'est de la maintenance
  • le code ne sera pas maintenu par la même personne pour toute la durée de vie du code
  • les conventions de codage permettent d'améliorer la lisibilité du code et une compréhension plus rapide d'un nouveau code

Cette convention de codage est tirée de site officiel de Sun directement : http://java.sun.com/docs/codeconv/html [...] vTOC.doc.html.
Le texte qui suit en est donc largement inspiré, mais est bien sûr simplifié à l'essentiel. Si vous souhaitez plus de détails c'est dont par là-bas que ça se passe.
Il y a également un PDF en français qui traite de ce sujet : http://cyberzoide.developpez.com/java/ [...] JavaStyle.pdf


Le nommage


Le nommage est très important, c'est ce qui va permette de comprendre de quoi on traite en lisant un code.

camelCase


Le camelCase c'est la manière la plus utilisée pour nommer en Java. CamelCase c'est tout simple, ça veut dire que chaque première lettre d'un mot prend une majuscule, que tous les mots sont collés les uns aux autres et petite subtitlité, le premier mot ne prend pas de majuscule. Pourquoi camelCase, parce que ça ressemble aux bosses d'un chameau...

Les packages


Généralement les packages sont nommés avec un nom de domaine en commençant par la fin et en ajoutant ensuite le nom du projet. Cela donnerait pour le projet NewWave du site du zéro quelque chose dans ce style : com.siteduzero.newwave
Nommer les packages de cette manière permet d'éviter des conflits entre des classes ayant ensuite le même nom et de bien s'y retrouver.

Les classes


Les classes sont nommées selon la méthode camelCase mais commencent pas une majuscule. Il faut aussi éviter les abréviations et essayer d'utiliser des mots qui décrivent bien la classe tout en étant pas trop long. Exemple : FenetrePrincipale, SelecteurDeFichiers, etc.
Les interfaces se nomment de la même manières que les classes.

Les méthodes


Les méthodes sont nommées selon la méthode camelCase et comportent généralement un verbe d'action. Cela donne par exemple : fermeLaFenetre(), donnerDeLArgent(), manger(), etc.

En plus de cela, il faut savoir que dans une classe on retrouve souvent des méthodes de type getter et setter (accesseur, modificateur), pour récupérer une variable de classe ou la modifier sans toucher directement à la variable. Il se nomme généralement getNomDeLaVariable() et setNomDeLaVariable(Object nomDeLaVariable). Il existe également d'autres mot-clés fréquemment utilisés comme add et remove (ajout, supprimer) pour ajouter et supprimer quelque chose : addQuelqueChose(Object quelqueChose), removeTout(), etc.

Les variables


Les variables se nomment également en camelCase et en commençant par une lettre (a-z). Le nom d'une variable devrait être court et clair. Les variables à 1 caractère sont à éviter sauf pour un usage temporaire (i, j, k, l, m, n pour les entiers et c, d , e pour les caractères). Cela donne par exemple : nombrePopcorn, tailleAppartement, i, etc.

Les constantes


Les constantes c'est-à-dire les "static final" doivent être écrites en majuscules et pour séparer les mots les "_" sont à utiliser. Cela donne par exemple : LARGEUR_MAX, ID_COURANT, etc.

Les commentaires


Les commentaires sont très utiles pour les programmeurs qui reprendront un code ou bien pour fournir une documentation sur le programme. Il existe la javadoc qui est un système permettant avec des tags de spécifier certains choses comme la date, l'auteur, la version, les arguments et autres.
Cette partie sera complétée plus tard

Exemple complet


J'ai repris une de mes sources pour cet exemple...
package ch.comem.fxsubtitlesvideoplayer.models;

/**
 * Classe permettant la gestion de sous-titres sous leur forme unitaire avec un
 * minimum d'informations : le texte, l'heure du début (en secondes) de l'affichage
 * et l'heure de fin (en secondes) de l'affichage du sous-titre.
 * <br /><br />
 * Elle possède également des méthodes pour convertir du texte d'un type de
 * sous-titres (Ex : SubRip)  * en un objet FXSubtitle ce qui est très pratique
 * pour importer un sous-titre de manière rapide. Exemple de fichier SubRip :
 * <br /><br />
 *                   1<br />
 *                   00:00:00,000 --> 00:00:02,499<br />
 *                   Précédemment dans Knight Rider
 * <br /><br />
 * De cette manière, tous les types de sous-titres pourraient être intégrés à
 * ce modèle simple de sous-titres.
 * 
 * @author janulrich00001
 * @version 1.0
 */
public class FXSubtitle implements Comparable<FXSubtitle> {

    /**
     * Le contenu du sous-titre sous forme de texte, dialogues, ...
     */
    private String content;
    /**
     * Le temps de début d'affichage du sous-titre en secondes
     */
    private double startTime;
    /**
     * Le temps de fin d'affichage du sous-titre en secondes
     */
    private double endTime;

    /**
     * Constructeur d'un sous-titre unitaire qui vérifie si le temps de début
     * est bien plus grand que le temps de fin et que les deux temps sont positifs
     * et dans les limites maximales du type Double.
     * @param content Le contenu du sous-titre
     * @param startTime Le temps de début d'affichage
     * @param endTime Le temps de fin d'affichage
     * @throws java.lang.Exception une exception est lancée si le contenu vaut null
     * ou si les temps sont invalides
     */
    public FXSubtitle(String content, double startTime, double endTime) throws Exception {
        if (content != null && startTime >= 0d && endTime > startTime && endTime <= Double.MAX_VALUE) {
            this.content = content;
            this.startTime = startTime;
            this.endTime = endTime;
        } else {
            throw new Exception("Contenu null ou temps invalides");
        }
    }

    /**
     * Rend le contenu du sous-titre
     * @return le contenu du sous-titre
     */
    public String getContent() {
        return content;
    }

    /**
     * Change le contenu du sous-titre s'il n'est pas null
     * @param content le nouveau contenu
     */
    public void setContent(String content) {
        if (content != null) {
            this.content = content;
        }
    }

    /**
     * Rend le temps de début
     * @return le temps de début
     */
    public double getStartTime() {
        return startTime;
    }

    /**
     * Change le temps de fin si celui-ci est positif et inférieur au temps de fin
     * @param startTime le temps de début
     */
    public void setStartTime(double startTime) {
        if (startTime >= 0d && startTime < endTime) {
            this.startTime = startTime;
        }
    }

    /**
     * Rend le temps de fin
     * @return le temps de fin
     */
    public double getEndTime() {
        return endTime;
    }

    /**
     * Change le temps de fin si celui-ci est supérieur au temps de début et
     * qu'il est inférieur au maximum autorisé par la type Double
     * @param endTime the endTime to set
     */
    public void setEndTime(double endTime) {
        if (endTime > startTime && endTime <= Double.MAX_VALUE) {
            this.endTime = endTime;
        }
    }

    /**
     * Décale le temps de début et le temps de fin positivement ou négativement
     * La méthode vérifie que la temps de début de sera pas négatif et que le
     * temps de fin soit toujours encore dans les limites du type Double
     * @param shift Le décalage à effectuer sur les temps
     * @return true si le décalage est effectif, false sinon
     */
    public boolean shiftTime(double shift) {
        boolean ok = false;
        if ((shift < 0d && (startTime + shift) >= 0d) || (shift > 0d && (endTime + shift) <= Double.MAX_VALUE)) {
            startTime += shift;
            endTime += shift;
            ok = true;
        }
        return ok;
    }

    /**
     * Méthode pour vérifier qu'un temps donné est compris entre le temps de début
     * et le temps de fin.
     * @param time le temps avec lequel comparé les temps
     * @return true si le temps est compris entre les temps, false sinon
     */
    public boolean isCoveredTime(double time) {
        boolean isCoveredTime = false;
        if (time >= startTime && time <= endTime) {
            isCoveredTime = true;
        }
        return isCoveredTime;
    }

    /**
     * Redéfinition de compareTo pour comparer deux sous-titres entre eux
     * Seuls les temps sont comparés et il en retourne si un sous-titre est affiché
     * avant ou après l'autre. Si les sous-titres s'entre-croisent 0 est retourné.
     * @param subtitle Le sous-titre auquel se comparer
     * @return -1 si il apparaît avant, 0 si les sous-titres s'entre-croisent, 1 sinon
     */
    @Override
    public int compareTo(FXSubtitle subtitle) {
        int result = 0;
        if (subtitle != null && endTime < subtitle.startTime) {
            result = -1;
        } else if (subtitle != null && startTime > subtitle.endTime) {
            result = 1;
        }
        return result;
    }

    /**
     * Redéfintion de la méthode equals pour comparer le contenu de 2 sous-titres
     * c'est-à-dire les temps de début et de fin ainsi que le contenu
     * @param o l'objet avec lequel faire le test d'égalité
     * @return true si le contenu est le même, false sinon
     */
    @Override
    public boolean equals(Object o) {
        boolean isEqual = false;
        if (o != null && o instanceof FXSubtitle) {
            isEqual = this.hashCode() == o.hashCode();
        }
        return isEqual;
    }

    /**
     * Redéfinition de la méthode hashCode qui sera utilisée dans la méthode
     * equlas pour comparer 2 sous-titres.
     * @return un hash du contenu et des temps du sous-titre
     */
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 71 * hash + (this.content != null ? this.content.hashCode() : 0);
        hash = 71 * hash + (int) (Double.doubleToLongBits(this.startTime) ^ (Double.doubleToLongBits(this.startTime) >>> 32));
        hash = 71 * hash + (int) (Double.doubleToLongBits(this.endTime) ^ (Double.doubleToLongBits(this.endTime) >>> 32));
        return hash;
    }

    /**
     * Redéfinition de la méthode clone pour cloner un sous-titre
     * @return un clone du sous-titre, null si le clonage a échoué
     */
    @Override
    public FXSubtitle clone() {
        FXSubtitle clone = null;
        try {
            clone = new FXSubtitle(new String(content), startTime, endTime);
        } catch (Exception ex) {
        }
        return clone;
    }

    /**
     * Méthode permettant de parser une string d'un sous-titre unitaire de
     * type SubRip en FXSubtitle.
     * @param input le texte représentant le sousàtire de type SubRip
     * @return un FXSubtitle si tout fonctionne, null si l'input est null ou ""
     * @throws java.lang.Exception si le texte à parser n'est pas transformable
     */
    public static FXSubtitle createFXSubtitleFromSubRip(String input) throws Exception {
        FXSubtitle sub = null;
        if (input != null && !input.equals("")) {
            String[] lines = input.split("\n");

            //Découpe le temps de début du sous-titre et le transforme en double
            String[] secondLine = lines[1].split(" ");
            String[] time = secondLine[0].split(":");
            String[] time2 = time[2].split(",");

            int hours1 = Integer.valueOf(time[0]);
            int minutes1 = Integer.valueOf(time[1]);
            int seconds1 = Integer.valueOf(time2[0]);
            int milliseconds1 = Integer.valueOf(time2[1]);

            double sTime = hours1 * 3600 + minutes1 * 60 + seconds1 + ((double) milliseconds1 / 1000);

            time = secondLine[2].split(":");
            time2 = time[2].split(",");

            //Découpe le temps de fin du sous-titre et le transforme en double
            int hours2 = Integer.valueOf(time[0]);
            int minutes2 = Integer.valueOf(time[1]);
            int seconds2 = Integer.valueOf(time2[0]);
            int milliseconds2 = Integer.valueOf(time2[1]);

            double eTime = hours2 * 3600 + minutes2 * 60 + seconds2 + ((double) milliseconds2 / 1000);

            //Récupère tout le texte du sous-titre
            int textCount = 2;
            String text = "";
            while (textCount <= lines.length - 1) {
                if (!text.equals("")) {
                    text += "\n";
                }
                text += lines[textCount];
                textCount++;
            }
            //Crée le sous-titre
            sub = new FXSubtitle(text, sTime, eTime);
        }
        return sub;
    }

    /**
     * Redéfinition de toString qui actuellement renvoie ce que retourne la
     * méthode toSubRip.
     * @return un texte représentant un sous-titre sous sa forme SubRip
     */
    @Override
    public String toString() {
        return toSubRip();
    }

    /**
     * Méthode permettant de générer un texte qui représente un sous-titre sous
     * sa forme SubRip. C'est-à-dire de cette manière :
     * <br /><br />
     *               00:00:00,000 --> 00:00:02,499<br />
     *               Précédemment dans Knight Rider
     * <br /><br />
     * Le numéro du sous-titre n'est pas ajouté à ce stade là. Car pour un
     * sous-titre unitaire son numéro n'est pas encore connu.
     * @return un texte représentant un sous-titre sous sa forme SubRip
     */
    public String toSubRip() {
        return subRipTime(startTime) + " --> " + subRipTime(endTime) + "\n" + content.replace("\n", "");
    }

    /**
     * Méthode pour transformer un double qui représente un temps sous une forme
     * humainement lisible : 01:12:55,123
     * @param time le temps
     * @return le temps sous sa forme lisisble
     */
    public static String subRipTime(double time) {
        String stringTime = String.valueOf(time);
        String[] split = stringTime.split("\\.");
        //Permet d'avoir toujours 3 chiffres pour les millisecondes
        String decimals = "000";
        StringBuffer decimalsBuffer = new StringBuffer();
        if (split.length > 1) {
            decimals = split[1];
            if (decimals.length() > 0) {
                decimalsBuffer.append(decimals.charAt(0));
            } else {
                decimalsBuffer.append(0);
            }
            if (decimals.length() > 1) {
                decimalsBuffer.append(decimals.charAt(1));
            } else {
                decimalsBuffer.append(0);
            }
            if (decimals.length() > 2) {
                decimalsBuffer.append(decimals.charAt(2));
            } else {
                decimalsBuffer.append(0);
            }
            decimals = decimalsBuffer.toString();
        }

        //Transformation des secondes en hh:mm:ss
        int seconds = Integer.valueOf(split[0]);
        String separator = ":";
        int minutes = (int) seconds / 60;
        int newSeconds = (int) seconds % 60;
        int hours = minutes / 60;
        int newMinutes = minutes % 60;
        StringBuffer s = new StringBuffer();
        if (hours < 10) {
            s.append(0);
        }
        s.append(hours).append(separator);
        if (newMinutes < 10) {
            s.append(0);
        }
        s.append(newMinutes).append(separator);
        if (newSeconds < 10) {
            s.append(0);
        }
        s.append(newSeconds);
        //Ajout des milliseconds
        s.append(",").append(decimals);
        return s.toString();
    }
}

Conclusion


J'estimais que ce topic était nécessaire dans ce forum de Java et que vous serez d'accord avec moi. Si c'était possible de mettre ce topic en post-it je pense que ça pourrait être très utile. Finalement si des ajouts/corrections étaient nécessaires, n'hésiter pas à m'en faire part.

Bonne journée ou soirée et surtout bon Java
  • Partager sur Facebook
  • Partager sur Twitter