Style de code Java AOSP pour les contributeurs

Les styles de code sur cette page sont des règles strictes pour la contribution de code Java au projet Open Source Android (AOSP). Les contributions à la plate-forme Android qui ne respectent pas ces règles ne sont généralement pas acceptées . Nous reconnaissons que tous les codes existants ne suivent pas ces règles, mais nous nous attendons à ce que tous les nouveaux codes soient conformes. Voir Codage avec respect pour des exemples de terminologie à utiliser et à éviter pour un écosystème plus inclusif.

Être cohérent

L'une des règles les plus simples est d'être cohérent. Si vous modifiez du code, prenez quelques minutes pour examiner le code environnant et déterminer son style. Si ce code utilise des espaces autour des clauses if , vous devriez également le faire. Si les commentaires de code sont entourés de petites boîtes d'étoiles, faites en sorte que vos commentaires soient également entourés de petites boîtes d'étoiles.

L'intérêt d'avoir des directives de style est d'avoir un vocabulaire commun de codage, afin que les lecteurs puissent se concentrer sur ce que vous dites, plutôt que sur la façon dont vous le dites. Nous présentons ici des règles de style globales afin que vous connaissiez le vocabulaire, mais le style local est également important. Si le code que vous ajoutez à un fichier semble radicalement différent du code existant qui l'entoure, il perturbe le rythme des lecteurs lorsqu'ils le lisent. Essayez d'éviter cela.

Règles du langage Java

Android suit les conventions de codage Java standard avec les règles supplémentaires décrites ci-dessous.

Ne pas ignorer les exceptions

Il peut être tentant d'écrire du code qui ignore une exception, comme :

  void setServerPort(String value) {
      try {
          serverPort = Integer.parseInt(value);
      } catch (NumberFormatException e) { }
  }

Ne fais pas ça. Bien que vous puissiez penser que votre code ne rencontrera jamais cette condition d'erreur ou qu'il n'est pas important de la gérer, ignorer ce type d'exception crée des mines dans votre code pour que quelqu'un d'autre se déclenche un jour. Vous devez gérer chaque exception dans votre code selon des principes ; la manipulation spécifique varie selon le cas.

" Chaque fois que quelqu'un a une clause de capture vide, il devrait avoir un sentiment effrayant. Il y a certainement des moments où c'est en fait la bonne chose à faire, mais au moins vous devez y penser. En Java, vous ne pouvez pas échapper au sentiment effrayant. " -James Gosling

Les alternatives acceptables (par ordre de préférence) sont :

  • Levez l'exception à l'appelant de votre méthode.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • Lancez une nouvelle exception appropriée à votre niveau d'abstraction.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • Gérez l'erreur avec élégance et substituez une valeur appropriée dans le bloc catch {} .
      /** Set port. If value is not a valid number, 80 is substituted. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            serverPort = 80;  // default port for server
        }
      }
    
  • Interceptez l'exception et lancez une nouvelle instance de RuntimeException . C'est dangereux, alors ne le faites que si vous êtes certain que si cette erreur se produit, la bonne chose à faire est de planter.
      /** Set port. If value is not a valid number, die. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("port " + value " is invalid, ", e);
        }
      }
    
  • En dernier recours, si vous êtes convaincu qu'ignorer l'exception est approprié, vous pouvez l'ignorer, mais vous devez également expliquer pourquoi avec une bonne raison.
    /** If value is not a valid number, original port number is used. */
    
    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Method is documented to just ignore invalid user input.
            // serverPort will just be unchanged.
        }
    }
    

Ne pas intercepter les exceptions génériques

Il peut être tentant d'être paresseux lorsqu'il s'agit d'attraper des exceptions et de faire quelque chose comme ceci :

  try {
      someComplicatedIOFunction();        // may throw IOException
      someComplicatedParsingFunction();   // may throw ParsingException
      someComplicatedSecurityFunction();  // may throw SecurityException
      // phew, made it all the way
  } catch (Exception e) {                 // I'll just catch all exceptions
      handleError();                      // with one generic handler!
  }

Ne fais pas ça. Dans presque tous les cas, il est inapproprié d'attraper une Exception générique ou Throwable (de préférence pas Throwable car il inclut des exceptions Error ). C'est dangereux car cela signifie que des exceptions auxquelles vous ne vous attendiez pas (y compris des exceptions d'exécution comme ClassCastException ) sont prises dans la gestion des erreurs au niveau de l'application. Cela masque les propriétés de gestion des échecs de votre code, ce qui signifie que si quelqu'un ajoute un nouveau type d'exception dans le code que vous appelez, le compilateur ne signalera pas que vous devez gérer l'erreur différemment. Dans la plupart des cas, vous ne devriez pas gérer différents types d'exceptions de la même manière.

La rare exception à cette règle est le code de test et le code de niveau supérieur où vous souhaitez détecter toutes sortes d'erreurs (pour les empêcher d'apparaître dans une interface utilisateur ou pour maintenir un travail par lots en cours d'exécution). Dans ces cas, vous pouvez intercepter une Exception générique (ou Throwable ) et gérer l'erreur de manière appropriée. Réfléchissez bien avant de faire cela, cependant, et mettez des commentaires expliquant pourquoi c'est sûr dans ce contexte.

Alternatives à la capture des exceptions génériques :

  • Interceptez chaque exception séparément dans le cadre d'un bloc multi-catch, par exemple :
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • Refactorisez votre code pour avoir une gestion des erreurs plus fine, avec plusieurs blocs try. Séparez les E/S de l'analyse et gérez les erreurs séparément dans chaque cas.
  • Relancez l'exception. Souvent, vous n'avez pas besoin d'attraper l'exception à ce niveau de toute façon, laissez simplement la méthode la lancer.

N'oubliez pas que les exceptions sont vos amies ! Lorsque le compilateur se plaint que vous n'attrapez pas une exception, ne vous renfrognez pas. Le sourire! Le compilateur vous permet simplement de détecter plus facilement les problèmes d'exécution dans votre code.

N'utilisez pas de finaliseurs

Les finaliseurs sont un moyen d'exécuter un morceau de code lorsqu'un objet est ramassé. Alors que les finaliseurs peuvent être pratiques pour le nettoyage (en particulier des ressources externes), il n'y a aucune garantie quant au moment où un finaliseur sera appelé (ou même qu'il sera appelé du tout).

Android n'utilise pas de finaliseurs. Dans la plupart des cas, vous pouvez utiliser une bonne gestion des exceptions à la place. Si vous avez absolument besoin d'un finaliseur, définissez une méthode close() (ou similaire) et documentez exactement quand cette méthode doit être appelée (voir InputStream pour un exemple). Dans ce cas, il est approprié mais pas obligatoire d'imprimer un court message de journal à partir du finaliseur, tant qu'il n'est pas prévu d'inonder les journaux.

Qualifier pleinement les importations

Lorsque vous souhaitez utiliser la classe Bar du package foo , il existe deux manières possibles de l'importer :

  • import foo.*;

    Réduit potentiellement le nombre d'instructions d'importation.

  • import foo.Bar;

    Rend évident quelles classes sont utilisées et le code est plus lisible pour les mainteneurs.

Utilisez import foo.Bar; pour importer tout le code Android. Une exception explicite est faite pour les bibliothèques standard Java ( java.util.* , java.io.* , etc.) et le code de test unitaire ( junit.framework.* ).

Règles de la bibliothèque Java

Il existe des conventions pour l'utilisation des bibliothèques et des outils Java d'Android. Dans certains cas, la convention a changé de manière importante et un code plus ancien peut utiliser un modèle ou une bibliothèque obsolète. Lorsque vous travaillez avec un tel code, vous pouvez conserver le style existant. Cependant, lors de la création de nouveaux composants, n'utilisez jamais de bibliothèques obsolètes.

Règles de style Java

Utiliser les commentaires standard Javadoc

Chaque fichier doit avoir une déclaration de copyright en haut, suivie des déclarations de package et d'importation (chaque bloc étant séparé par une ligne vide), et enfin de la déclaration de classe ou d'interface. Dans les commentaires Javadoc, décrivez ce que fait la classe ou l'interface.

/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */

public class Foo {
    ...
}

Chaque classe et méthode publique non triviale que vous écrivez doit contenir un commentaire Javadoc avec au moins une phrase décrivant ce que fait la classe ou la méthode. Cette phrase doit commencer par un verbe descriptif à la troisième personne.

Exemples

/** Returns the correctly rounded positive square root of a double value. */

static double sqrt(double a) {
    ...
}

ou

/**
 * Constructs a new String by converting the specified array of
 * bytes using the platform's default character encoding.
 */
public String(byte[] bytes) {
    ...
}

Vous n'avez pas besoin d'écrire Javadoc pour des méthodes triviales get et set telles que setFoo() si tout ce que votre Javadoc dirait est "sets Foo". Si la méthode fait quelque chose de plus complexe (comme l'application d'une contrainte ou a un effet secondaire important), alors vous devez la documenter. Si la signification de la propriété "Foo" n'est pas évidente, vous devez la documenter.

Chaque méthode que vous écrivez, publique ou autre, bénéficierait de Javadoc. Les méthodes publiques font partie d'une API et nécessitent donc Javadoc. Android n'impose pas de style spécifique pour écrire des commentaires Javadoc, mais vous devez suivre les instructions de Comment écrire des commentaires de document pour l'outil Javadoc .

Écrire des méthodes courtes

Lorsque cela est possible, gardez les méthodes petites et ciblées. Nous reconnaissons que les méthodes longues sont parfois appropriées, de sorte qu'aucune limite stricte n'est imposée à la longueur de la méthode. Si une méthode dépasse 40 lignes environ, demandez-vous si elle peut être décomposée sans nuire à la structure du programme.

Définir des champs dans des emplacements standard

Définissez les champs soit en haut du fichier, soit juste avant les méthodes qui les utilisent.

Limiter la portée des variables

Gardez la portée des variables locales au minimum. Cela augmente la lisibilité et la maintenabilité de votre code et réduit le risque d'erreur. Déclarez chaque variable dans le bloc le plus interne qui contient toutes les utilisations de la variable.

Déclarez les variables locales au point où elles sont utilisées pour la première fois. Presque chaque déclaration de variable locale doit contenir un initialiseur. Si vous ne disposez pas encore de suffisamment d'informations pour initialiser une variable de manière sensée, reportez la déclaration jusqu'à ce que vous en ayez.

L'exception concerne les instructions try-catch. Si une variable est initialisée avec la valeur de retour d'une méthode qui lève une exception vérifiée, elle doit être initialisée à l'intérieur d'un bloc try. Si la valeur doit être utilisée en dehors du bloc try, alors elle doit être déclarée avant le bloc try, où elle ne peut pas encore être initialisée de manière sensée :

// Instantiate class cl, which represents some sort of Set

Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}

// Exercise the set
s.addAll(Arrays.asList(args));

Cependant, vous pouvez même éviter ce cas en encapsulant le bloc try-catch dans une méthode :

Set createSet(Class cl) {
    // Instantiate class cl, which represents some sort of Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

Déclarez les variables de boucle dans l'instruction for elle-même à moins qu'il n'y ait une raison impérieuse de faire autrement :

for (int i = 0; i < n; i++) {
    doSomething(i);
}

et

for (Iterator i = c.iterator(); i.hasNext(); ) {
    doSomethingElse(i.next());
}

Commander des relevés d'importation

L'ordre des déclarations d'importation est :

  1. Importations Android
  2. Importations de tiers ( com , junit , net , org )
  3. java et javax

Pour correspondre exactement aux paramètres de l'IDE, les importations doivent être :

  • Alphabétique au sein de chaque groupe, avec des majuscules avant les minuscules (par exemple, Z avant a)
  • Séparé par une ligne vide entre chaque groupe majeur ( android , com , junit , net , org , java , javax )

À l'origine, il n'y avait aucune exigence de style sur la commande, ce qui signifie que les IDE changeaient toujours la commande ou que les développeurs IDE devaient désactiver les fonctionnalités de gestion automatique des importations et maintenir manuellement les importations. Cela a été jugé mauvais. Lorsque le style Java a été demandé, les styles préférés variaient énormément et Android devait simplement "choisir une commande et être cohérent". Nous avons donc choisi un style, mis à jour le guide de style et fait en sorte que les IDE y obéissent. Nous nous attendons à ce que lorsque les utilisateurs de l'IDE travaillent sur le code, les importations dans tous les packages correspondent à ce modèle sans effort d'ingénierie supplémentaire.

Nous avons choisi ce style tel que :

  • Les importations que les gens veulent regarder en premier ont tendance à être en haut ( android ).
  • Les importations que les gens veulent au moins regarder ont tendance à être en bas ( java ).
  • Les humains peuvent facilement suivre le style.
  • Les IDE peuvent suivre le style.

Placez les importations statiques au-dessus de toutes les autres importations commandées de la même manière que les importations régulières.

Utiliser des espaces pour l'indentation

Nous utilisons quatre (4) tirets d'espace pour les blocs et jamais les tabulations. En cas de doute, soyez cohérent avec le code environnant.

Nous utilisons huit (8) retraits d'espace pour les retours à la ligne, y compris les appels de fonction et les affectations.

conseillé

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

Non recommandé

Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);

Suivre les conventions de nommage des champs

  • Les noms de champs non publics et non statiques commencent par m .
  • Les noms de champs statiques commencent par s .
  • Les autres champs commencent par une lettre minuscule.
  • Les champs finaux statiques (constants, profondément immuables) sont ALL_CAPS_WITH_UNDERSCORES .

Par exemple:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}

Utiliser le style d'accolade standard

Mettez les accolades sur la même ligne que le code qui les précède, pas sur leur propre ligne :

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

Nous avons besoin d'accolades autour des déclarations pour un conditionnel. Exception : si le conditionnel entier (la condition et le corps) tient sur une seule ligne, vous pouvez (mais n'y êtes pas obligé) tout mettre sur une seule ligne. Par exemple, ceci est acceptable :

if (condition) {
    body();
}

et c'est acceptable :

if (condition) body();

mais ce n'est pas acceptable :

if (condition)
    body();  // bad!

Limiter la longueur de la ligne

Chaque ligne de texte de votre code doit comporter au maximum 100 caractères. Bien que de nombreuses discussions aient entouré cette règle, la décision reste que 100 caractères est le maximum avec les exceptions suivantes :

  • Si une ligne de commentaire contient un exemple de commande ou une URL littérale de plus de 100 caractères, cette ligne peut comporter plus de 100 caractères pour faciliter le copier-coller.
  • Les lignes d'importation peuvent dépasser la limite car les humains les voient rarement (cela simplifie également l'écriture d'outils).

Utiliser les annotations Java standard

Les annotations doivent précéder les autres modificateurs pour le même élément de langage. Des annotations de marqueur simples (par exemple, @Override ) peuvent être répertoriées sur la même ligne avec l'élément de langue. S'il existe plusieurs annotations ou des annotations paramétrées, répertoriez-les une par ligne dans l'ordre alphabétique.

Les pratiques standard d'Android pour les trois annotations prédéfinies en Java sont :

  • Utilisez l'annotation @Deprecated chaque fois que l'utilisation de l'élément annoté est déconseillée. Si vous utilisez l'annotation @Deprecated , vous devez également avoir une balise Javadoc @deprecated et elle doit nommer une implémentation alternative. De plus, rappelez-vous qu'une méthode @Deprecated est toujours censée fonctionner . Si vous voyez un ancien code contenant une balise Javadoc @deprecated , ajoutez l'annotation @Deprecated .
  • Utilisez l'annotation @Override chaque fois qu'une méthode remplace la déclaration ou l'implémentation d'une superclasse. Par exemple, si vous utilisez la balise Javadoc @inheritdocs et dérivez d'une classe (et non d'une interface), vous devez également indiquer que la méthode remplace la méthode de la classe parente.
  • Utilisez l'annotation @SuppressWarnings uniquement dans les cas où il est impossible d'éliminer un avertissement. Si un avertissement réussit ce test "impossible à éliminer", l'annotation @SuppressWarnings doit être utilisée pour garantir que tous les avertissements reflètent les problèmes réels dans le code.

    Lorsqu'une annotation @SuppressWarnings est nécessaire, elle doit être précédée d'un commentaire TODO expliquant la condition "impossible à éliminer". Cela identifie normalement une classe incriminée qui a une interface maladroite. Par exemple:

    // TODO: The third-party class com.third.useful.Utility.rotate() needs generics
    @SuppressWarnings("generic-cast")
    List<String> blix = Utility.rotate(blax);
    

    Lorsqu'une annotation @SuppressWarnings est requise, refactorisez le code pour isoler les éléments logiciels auxquels l'annotation s'applique.

Traiter les acronymes comme des mots

Traitez les acronymes et les abréviations comme des mots dans les variables de nommage, les méthodes et les classes pour rendre les noms plus lisibles :

Bien Mal
XmlHttpRequestXmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
classe Html HTML de classe
URL de la chaîne URL de chaîne
identifiant long identifiant long

Comme les bases de code JDK et Android sont incohérentes autour des acronymes, il est pratiquement impossible d'être cohérent avec le code environnant. Par conséquent, traitez toujours les acronymes comme des mots.

Utiliser les commentaires TODO

Utilisez les commentaires TODO pour le code temporaire, une solution à court terme ou assez bon mais pas parfait. Ces commentaires doivent inclure la chaîne TODO en majuscules, suivie de deux-points :

// TODO: Remove this code after the UrlTable2 has been checked in.

et

// TODO: Change this to use a flag instead of a constant.

Si votre TODO est de la forme "À une date future, faites quelque chose", assurez-vous d'inclure une date spécifique ("Réparer d'ici novembre 2005") ou un événement spécifique ("Supprimer ce code après que tous les mélangeurs de production comprennent le protocole V7". ).

Connectez-vous avec parcimonie

Bien que la journalisation soit nécessaire, elle a un impact négatif sur les performances et perd de son utilité si elle n'est pas maintenue raisonnablement concise. Les installations de journalisation offrent cinq niveaux différents de journalisation :

  • ERROR : À utiliser lorsque quelque chose de fatal s'est produit, c'est-à-dire que quelque chose aura des conséquences visibles pour l'utilisateur et ne pourra pas être récupéré sans supprimer certaines données, désinstaller des applications, effacer les partitions de données ou reflasher l'intégralité de l'appareil (ou pire). Ce niveau est toujours enregistré. Les problèmes qui justifient une journalisation au niveau ERROR sont de bons candidats pour être signalés à un serveur de collecte de statistiques.
  • WARNING : À utiliser lorsqu'un événement grave et inattendu s'est produit, c'est-à-dire un événement qui aura des conséquences visibles pour l'utilisateur mais qui est susceptible d'être récupérable sans perte de données en effectuant une action explicite, allant de l'attente ou du redémarrage d'une application jusqu'au retéléchargement une nouvelle version d'une application ou en redémarrant l'appareil. Ce niveau est toujours enregistré. Les problèmes qui justifient la journalisation au niveau WARNING peuvent également être pris en compte pour les rapports à un serveur de collecte de statistiques.
  • INFORMATIVE : Utilisé pour noter que quelque chose d'intéressant s'est produit, c'est-à-dire lorsqu'une situation est détectée qui est susceptible d'avoir un impact généralisé, mais n'est pas nécessairement une erreur. Une telle condition ne doit être consignée que par un module qui estime qu'il est le plus autoritaire dans ce domaine (pour éviter la journalisation en double par des composants ne faisant pas autorité). Ce niveau est toujours enregistré.
  • DEBUG : permet de noter plus en détail ce qui se passe sur l'appareil et qui pourrait être pertinent pour enquêter et déboguer des comportements inattendus. Enregistrez uniquement ce qui est nécessaire pour recueillir suffisamment d'informations sur ce qui se passe avec votre composant. Si vos journaux de débogage dominent le journal, vous devez utiliser une journalisation détaillée.

    Ce niveau est enregistré même sur les versions de version et doit être entouré d'un if (LOCAL_LOG) ou if LOCAL_LOGD) , où LOCAL_LOG[D] est défini dans votre classe ou sous-composant, de sorte qu'il est possible de désactiver tous ces journaux . Par conséquent, il ne doit y avoir aucune logique active dans un bloc if (LOCAL_LOG) . Toute la chaîne de construction du journal doit également être placée dans le bloc if (LOCAL_LOG) . Ne refactorisez pas l'appel de journalisation dans un appel de méthode si cela entraîne la construction de la chaîne en dehors du bloc if (LOCAL_LOG) .

    Il y a du code qui dit encore if (localLOGV) . Ceci est également considéré comme acceptable, bien que le nom ne soit pas standard.

  • VERBOSE : À utiliser pour tout le reste. Ce niveau n'est connecté qu'aux versions de débogage et doit être entouré d'un bloc if (LOCAL_LOGV) (ou équivalent) afin qu'il puisse être compilé par défaut. Toute construction de chaîne est supprimée des versions de version et doit apparaître dans le bloc if (LOCAL_LOGV) .

Remarques

  • Dans un module donné, autre qu'au niveau VERBOSE , une erreur ne doit être signalée qu'une seule fois si possible. Dans une seule chaîne d'appels de fonction au sein d'un module, seule la fonction la plus interne doit renvoyer l'erreur, et les appelants du même module ne doivent ajouter une journalisation que si cela aide de manière significative à isoler le problème.
  • Dans une chaîne de modules, autre qu'au niveau VERBOSE , lorsqu'un module de niveau inférieur détecte des données invalides provenant d'un module de niveau supérieur, le module de niveau inférieur ne doit enregistrer cette situation que dans le journal DEBUG , et uniquement si la journalisation fournit informations qui ne sont pas autrement disponibles pour l'appelant. Plus précisément, il n'est pas nécessaire de consigner les situations dans lesquelles une exception est levée (l'exception doit contenir toutes les informations pertinentes) ou dans lesquelles les seules informations consignées sont contenues dans un code d'erreur. Ceci est particulièrement important dans l'interaction entre le framework et les applications, et les conditions causées par des applications tierces qui sont correctement gérées par le framework ne doivent pas déclencher une journalisation supérieure au niveau DEBUG . Les seules situations qui doivent déclencher la journalisation au niveau INFORMATIVE ou supérieur sont lorsqu'un module ou une application détecte une erreur à son propre niveau ou provenant d'un niveau inférieur.
  • Lorsqu'une condition qui justifierait normalement une journalisation est susceptible de se produire plusieurs fois, il peut être judicieux d'implémenter un mécanisme de limitation de débit pour éviter de déborder les journaux avec de nombreuses copies en double des mêmes informations (ou très similaires).
  • Les pertes de connectivité réseau sont considérées comme courantes et sont tout à fait attendues, et ne doivent pas être consignées gratuitement. Une perte de connectivité réseau qui a des conséquences au sein d'une application doit être consignée au niveau DEBUG ou VERBOSE (selon que les conséquences sont suffisamment graves et suffisamment inattendues pour être consignées dans une version de version).
  • Avoir un système de fichiers complet sur un système de fichiers accessible à ou au nom d'applications tierces ne doit pas être enregistré à un niveau supérieur à INFORMATIF.
  • Les données non valides provenant de toute source non fiable (y compris tout fichier sur un stockage partagé ou les données provenant d'une connexion réseau) sont considérées comme attendues et ne doivent pas déclencher de journalisation à un niveau supérieur à DEBUG lorsqu'elles sont détectées comme non valides (et même alors la journalisation doit être aussi limité que possible).
  • Lorsqu'il est utilisé sur des objets String , l'opérateur + crée implicitement une instance StringBuilder avec la taille de tampon par défaut (16 caractères) et potentiellement d'autres objets String temporaires. Ainsi, la création explicite d'objets StringBuilder n'est pas plus coûteuse que de s'appuyer sur l'opérateur + par défaut (et peut être beaucoup plus efficace). Gardez à l'esprit que le code qui appelle Log.v() est compilé et exécuté sur les versions de version, y compris la construction des chaînes, même si les journaux ne sont pas lus.
  • Toute journalisation destinée à être lue par d'autres personnes et à être disponible dans les versions de version doit être concise sans être cryptique et doit être compréhensible. Cela inclut toutes les connexions jusqu'au niveau DEBUG .
  • Dans la mesure du possible, continuez à vous connecter sur une seule ligne. Les longueurs de ligne jusqu'à 80 ou 100 caractères sont acceptables. Évitez les longueurs supérieures à environ 130 ou 160 caractères (y compris la longueur de la balise) si possible.
  • Si la journalisation rapporte des succès, ne l'utilisez jamais à des niveaux supérieurs à VERBOSE .
  • Si vous utilisez la journalisation temporaire pour diagnostiquer un problème difficile à reproduire, conservez-le au niveau DEBUG ou VERBOSE et joignez-le à des blocs if qui permettent de le désactiver au moment de la compilation.
  • Faites attention aux fuites de sécurité via le journal. Évitez de consigner des informations privées. En particulier, évitez de consigner des informations sur le contenu protégé. Ceci est particulièrement important lors de l'écriture de code cadre car il n'est pas facile de savoir à l'avance ce qui sera et ne sera pas une information privée ou un contenu protégé.
  • N'utilisez jamais System.out.println() (ou printf() pour le code natif). System.out et System.err sont redirigés vers /dev/null , de sorte que vos instructions d'impression n'ont aucun effet visible. Cependant, toute la construction de chaînes qui se produit pour ces appels est toujours exécutée.
  • La règle d'or de la journalisation est que vos journaux ne peuvent pas inutilement pousser d'autres journaux hors du tampon, tout comme d'autres ne peuvent pas sortir le vôtre.

Règles de style Javatests

Suivez les conventions de dénomination des méthodes de test et utilisez un trait de soulignement pour séparer ce qui est testé du cas spécifique testé. Ce style permet de voir plus facilement quels cas sont testés. Par exemple:

testMethod_specificCase1 testMethod_specificCase2

void testIsDistinguishable_protanopia() {
    ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
    assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
    assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}