web-dev-qa-db-fra.com

Java pour les variables finales statiques

il y a une règle qui dit:

Les noms représentant des constantes (variables finales) doivent être en majuscules, avec des traits de soulignement pour séparer les mots (extrait de http://geosoft.no/development/javastyle.html )

cela fonctionne très bien pour les types primitifs comme int ou strings:

private static final int MAX_COUNT = 10;

Mais qu'en est-il des types non primitifs? Dans la plupart des cas, j'ai vu ce qui suit:

private static final Logger log = Logger.getLogger(MyClass.class);

ou en singletons, où variable d'instance n'est pas en majuscule.

La question est de savoir quel est le bon moyen de déclarer ces types de variables (telles que log et instance)?

85
Aleksey

C'est toujours une constante . Voir le JLS pour plus d'informations sur la convention de dénomination des constantes. Mais en réalité, tout est une question de préférence.


Les noms des constantes dans les types d'interface doivent être, et final les variables de types de classe peuvent être classiquement, une séquence d'un ou plusieurs mots, acronymes ou abréviations, toutes en majuscules, avec des composants séparés par un tiret bas "_" personnages. Les noms constants doivent être descriptifs et non abrégés inutilement. Classiquement, ils peuvent être une partie appropriée du discours. Exemples de noms de constantes: MIN_VALUE, MAX_VALUE, MIN_RADIX, et MAX_RADIX de la classe Character.

Un groupe de constantes représentant les valeurs alternatives d'un ensemble ou, moins fréquemment, les bits de masquage dans une valeur entière, est parfois utilement spécifié avec un acronyme commun comme préfixe de nom, comme dans:

interface ProcessStates {
  int PS_RUNNING = 0;
  int PS_SUSPENDED = 1;
}

L'obscurcissement impliquant des noms constants est rare:

  • Les noms de constante n'ont normalement pas de lettres minuscules, ils ne masqueront donc normalement pas les noms de paquetages ou de types, ni les champs ombrés, dont les noms contiennent généralement au moins une lettre minuscule.
  • Les noms constants ne peuvent pas masquer les noms de méthodes, car ils sont distingués syntaxiquement.
66
mre

Le dialogue à ce sujet semble être l'antithèse de la conversation sur la désignation des classes interface et abstract. Je trouve cela alarmant et pense que la décision est beaucoup plus profonde que de simplement choisir une convention de nommage et de l’utiliser toujours avec static final.

Résumé et interface

Lors de la désignation d'interfaces et de classes abstraites, la convention acceptée a évolué de manière à ne pas préfixer ou ajouter de suffixe à votre abstract class Ou à votre interface avec des informations d'identification qui indiqueraient qu'il s'agit d'une autre classe.

public interface Reader {}
public abstract class FileReader implements Reader {}
public class XmlFileReader extends FileReader {}

On dit que le développeur n'a pas besoin de savoir que les classes ci-dessus sont abstract ou un interface.

Finale statique

Ma préférence personnelle et ma conviction sont que nous devrions suivre une logique similaire lorsque nous faisons référence à des variables static final. Au lieu de cela, nous évaluons son utilisation pour déterminer comment le nommer. Il semble que l'argument des majuscules soit quelque chose qui a été adopté à l'aveugle des langages C et C++. À mon avis, cela ne justifie pas de poursuivre la tradition en Java.

Question d'intention

Nous devrions nous demander quelle est la fonction de static final Dans notre propre contexte. Voici trois exemples d'utilisation de static final Dans différents contextes :

public class ChatMessage {
    //Used like a private variable
    private static final Logger logger = LoggerFactory.getLogger(XmlFileReader.class);

    //Used like an Enum
    public class Error {
        public static final int Success = 0;
        public static final int TooLong = 1;
        public static final int IllegalCharacters = 2;
    }

    //Used to define some static, constant, publicly visible property
    public static final int MAX_SIZE = Integer.MAX_VALUE;
}

Pourriez-vous utiliser toutes les majuscules dans les trois scénarios? Absolument, mais je pense que l’on peut soutenir que cela nuirait à l’objectif de chacun. Alors, examinons chaque cas individuellement.


Objet: Variable privée

Dans le cas de l'exemple Logger ci-dessus, le consignateur est déclaré comme privé et ne sera utilisé que dans la classe ou éventuellement dans une classe interne. Même s'il a été déclaré à protected ou package visibilité, son utilisation est la même:

public void send(final String message) {
    logger.info("Sending the following message: '" + message + "'.");
    //Send the message
}

Ici , nous ne nous soucions pas que logger soit une variable membre static final. Il pourrait simplement s'agir d'une variable d'instance final. Nous ne savons pas On n'a pas besoin de savoir. Tout ce que nous avons besoin de savoir, c'est que nous enregistrons le message dans le consignateur fourni par l'instance de classe.

public class ChatMessage {
    private final Logger logger = LoggerFactory.getLogger(getClass());
}

Vous ne nommeriez pas cela LOGGER dans ce scénario, alors pourquoi devriez-vous le nommer en majuscule s'il s'agissait de static final? Son contexte, ou son intention, est identique dans les deux cas.

Remarque: j’ai inversé ma position sur la visibilité package car elle ressemble plus à une forme d’accès public, limitée au niveau package.


But: Enum

Maintenant, vous pourriez dire, pourquoi utilisez-vous des entiers static final En tant que enum? C’est une discussion qui évolue encore et je dirais même semi-controversée, je vais donc essayer de ne pas faire dérailler cette discussion trop longtemps en s’y aventurant. Toutefois, il est suggéré de mettre en œuvre le modèle d’énumération accepté suivant:

public enum Error {
    Success(0),
    TooLong(1),
    IllegalCharacters(2);

    private final int value;

    private Error(final int value) {
        this.value = value;
    }

    public int value() {
        return value;
    }

    public static Error fromValue(final int value) {
        switch (value) {
        case 0:
            return Error.Success;
        case 1:
            return Error.TooLong;
        case 2:
            return Error.IllegalCharacters;
        default:
            throw new IllegalArgumentException("Unknown Error value.");
        }
    }
}

Il existe des variantes de ce qui précède qui permettent la conversion explicite de enum->int Et de int->enum. Dans le cadre de la diffusion en continu de ces informations sur un réseau, la sérialisation native Java est simplement trop détaillée. Un simple int, short ou byte pourrait économiser une bande passante considérable. Je pourrais plonger dans une comparaison longue et contrastée à propos des avantages et inconvénients de enum vs static final int impliquant la sécurité de type , lisibilité, maintenabilité, etc., heureusement, cela sort du cadre de cette discussion.

La ligne du bas est ceci, parfois static final int Sera utilisé comme une structure de style enum.

Si vous pouvez vous faire accepter que la déclaration ci-dessus est vraie , nous pourrons en discuter avec le style. Lors de la déclaration d'un enum, le style accepté indique que nous ne faisons pas ce qui suit:

public enum Error {
    SUCCESS(0),
    TOOLONG(1),
    ILLEGALCHARACTERS(2);
}

Au lieu de cela, nous faisons ce qui suit:

public enum Error {
    Success(0),
    TooLong(1),
    IllegalCharacters(2);
}

Si votre bloc d'entiers static final Sert de enum lâche, pourquoi devriez-vous utiliser une convention de dénomination différente pour celui-ci? Son contexte, ou son intention, est identique dans les deux cas.


Objet: Statique, constante, propriété publique

Cette utilisation est peut-être la plus nuageuse et la plus discutable. La constante statique taille est l'exemple d'utilisation le plus fréquent. Java supprime le besoin de sizeof() , mais il est parfois important de savoir combien d'octets une structure de données occupera.

Par exemple, considérons que vous écrivez ou lisez une liste de structures de données dans un fichier binaire, et le format de ce fichier binaire nécessite que la taille totale du bloc de données soit insérée avant les données réelles. Ceci est courant pour qu'un lecteur sache, quand les données s'arrêtent dans le scénario, qu'il y a plus de données, non liées, qui suivent. Considérez le format de fichier constitué suivant:

File Format: MyFormat (MYFM) for example purposes only
[int filetype: MYFM]
[int version: 0] //0 - Version of MyFormat file format
[int dataSize: 325] //The data section occupies the next 325 bytes
[int checksumSize: 400] //The checksum section occupies 400 bytes after the data section (16 bytes each)
[byte[] data]
[byte[] checksum]

Ce fichier contient une liste d'objets MyObject sérialisés dans un flux d'octets et écrits dans ce fichier. Ce fichier contient 325 octets d'objets MyObject, mais sans connaître la taille de chacun MyObject, vous n'avez aucun moyen de savoir quels octets appartiennent à chacun MyObject. Donc, vous définissez la taille de MyObject sur MyObject:

public class MyObject {
    private final long id; //It has a 64bit identifier (+8 bytes)
    private final int value; //It has a 32bit integer value (+4 bytes)
    private final boolean special; //Is it special? (+1 byte)

    public static final int SIZE = 13; //8 + 4 + 1 = 13 bytes
}

La structure de données MyObject occupera 13 octets lors de son écriture dans le fichier tel que défini ci-dessus. Sachant cela, lors de la lecture de notre fichier binaire, nous pouvons déterminer dynamiquement le nombre d'objets MyObject suivis dans le fichier:

int dataSize = buffer.getInt();
int totalObjects = dataSize / MyObject.SIZE;

Cela semble être le cas d'utilisation typique et l'argument de toutes les constantes majuscules static final, Et je conviens que dans ce contexte, toute majuscule a un sens. Voici pourquoi:

Java n'a pas de classe struct comme le langage C, mais un struct est simplement une classe avec tous les membres publics et aucun constructeur. C'est simplement une donnée struct. Donc, vous pouvez déclarer un class dans struct comme dans fashion:

public class MyFile {
    public static final int MYFM = 0x4D59464D; //'MYFM' another use of all uppercase!

    //The struct
    public static class MyFileHeader {
        public int fileType = MYFM;
        public int version = 0;
        public int dataSize = 0;
        public int checksumSize = 0;
    }
}

Permettez-moi de commencer cet exemple en déclarant que, personnellement, je n'analyserais pas de cette manière. Je suggérerais plutôt une classe immuable qui gère l'analyse en interne en acceptant un ByteBuffer ou les 4 variables comme arguments de constructeur. Cela dit, accéder (définir dans ce cas) les membres de ce struct ressemblerait à quelque chose comme:

MyFileHeader header = new MyFileHeader();
header.fileType     = buffer.getInt();
header.version      = buffer.getInt();
header.dataSize     = buffer.getInt();
header.checksumSize = buffer.getInt();

Ce ne sont pas static ou final, mais ce sont des membres exposés publiquement qui peuvent être définis directement. Pour cette raison, je pense que lorsqu'un membre static final Est exposé publiquement, il est logique de le mettre entièrement en majuscule. C’est la seule fois où est important pour le distinguer des variables publiques non statiques.

Remarque: même dans ce cas, si un développeur tentait de définir une variable final, il se heurterait à une erreur IDE ou au compilateur).


Sommaire

En conclusion, la convention que vous choisissez pour les variables static final Va être votre préférence, mais je crois fermement que le contexte d'utilisation devrait peser lourdement sur votre décision de conception. Ma recommandation personnelle serait de suivre l'une des deux méthodologies suivantes:

Méthodologie 1: Évaluer le contexte et l'intention [highly subjective; logical]

  • S'il s'agit d'une variable private qui ne devrait pas être distinguable d'une variable d'instance private, donnez-leur un nom identique. tout en minuscule
  • Si l'intention est de servir de type de bloc de style enum lâche de valeurs static, nommez-le comme vous le feriez avec un enum. cas Pascal: initial-cap chaque mot
  • Si son intention est de définir une propriété statique, constante et accessible au public, laissez-la ressortir en la rendant tout en majuscule

Méthodologie 2: Privé vs public [objective; logical]

La méthodologie 2 concentre essentiellement son contexte sur la visibilité et ne laisse aucune place à l’interprétation.

  • Si c'est private ou protected, alors il devrait être tout en minuscule .
  • Si c'est public ou package, alors il devrait être tout en majuscule .

Conclusion

Voici comment je vois la convention de nommage des variables static final. Je ne pense pas que ce soit quelque chose qui puisse ou devrait être mis dans une seule prise. Je crois que vous devriez évaluer son intention avant de décider comment le nommer.

Cependant, l'objectif principal doit être d'essayer de rester cohérent tout au long de la portée de votre projet/package. En fin de compte, c'est tout ce que vous avez le contrôle.

(Je m'attends à rencontrer de la résistance, mais espère également recueillir l'appui de la communauté sur cette approche. Quelle que soit votre position, restez poli s'il vous plaît lorsque vous reprenez, critiquez ou applaudissez ce choix de style.)

41
crush

La langue ne s'en soucie pas. L'important est de respecter les styles et conventions établis du projet sur lequel vous travaillez, afin que les autres responsables (ou vous dans cinq mois) aient la meilleure chance de ne pas être confondus.

Je pense qu'un nom entièrement majuscule pour un objet mutable m'embrouillerait certainement, même si la référence à cet objet était stockée dans un static final variable.

10
Henning Makholm

Eh bien c'est une question très intéressante. Je diviserais les deux constantes de votre question en fonction de leur type. int MAX_COUNT Est une constante de type primitif alors que Logger log Est un type non primitif.

Lorsque nous utilisons une constante de types primitifs, nous ne mutons la constante qu'une seule fois dans notre code public static final in MAX_COUNT = 10 Et nous accédons simplement à la valeur de la constante ailleurs for(int i = 0; i<MAX_COUNT; i++). C'est la raison pour laquelle nous sommes à l'aise avec l'utilisation de cette convention.

Alors que dans le cas des types non primitifs, bien que nous initialisions la constante dans un seul endroit private static final Logger log = Logger.getLogger(MyClass.class);, nous sommes supposés muter ou appeler une méthode sur cette constante ailleurs log.debug("Problem"). Nous, les gars, n'aimons pas mettre un opérateur de point après les caractères majuscules. Après tout, nous devons mettre un nom de fonction après l’opérateur point, qui sera sûrement un nom de casse-chameau. C'est pourquoi LOG.debug("Problem") semblerait maladroit.

Il en est de même avec les types String. En général, nous ne mutons pas ou n'appelons pas de méthode sur une constante String dans notre code. C'est pourquoi nous utilisons la convention de dénomination capital pour un objet de type String.

7
Kashif Nazar

Une référence constante à un objet n'est pas une constante, c'est simplement une référence constante à un objet.

private static final n'est pas ce qui définit ou non quelque chose. C’est juste le moyen Java de définir une constante, mais cela ne signifie pas que tous les private static final déclaration a été mis là pour définir une constante.

Quand j'écris private static final Logger Je ne cherche pas à définir une constante, je cherche simplement à définir une référence à un objet qui est private (il n'est pas accessible depuis d'autres classes), static ( qu’il s’agit d’une variable au niveau de la classe, aucune instance n’est nécessaire) et final (qui ne peut être attribué qu’une fois). Si cela coïncide avec le chemin Java s'attend à ce que vous déclariez une constante, eh bien, pas de chance, mais cela ne la rend pas constante. Je me moque de ce que le compilateur, sonar , ou n'importe quel Java guru dit. Une valeur constante, comme MILLISECONDS_IN_A_SECOND = 1000 est une chose et une référence constante à un objet en est une autre.

On sait que l'or brille, mais tout ce qui brille n'est pas or.

5
Eduardo

Il n'y a pas de "bonne" voie - il n'y a que des conventions. Vous avez énoncé la convention la plus commune, et celle que je suis dans mon propre code: tous les finales statiques devraient être en majuscules. J'imagine que d'autres équipes suivent d'autres conventions.

4

À mon avis, une variable "constante" est souvent un détail d'implémentation et ne justifie pas nécessairement des conventions de dénomination différentes. Cela peut aider à la lisibilité, mais cela peut aussi le blesser dans certains cas.

2
Cellux

Ces variables sont des constantes, à savoir private static final qu'ils soient nommés en majuscule ou non. La convention des majuscules montre simplement qu'il est évident que ces variables doivent être des constantes, mais ce n'est pas obligatoire. j'ai vu

private static final Logger log = Logger.getLogger(MyClass.class);

en minuscule auparavant, et cela me convient car je sais que l’enregistreur n’est utilisé que pour consigner les messages, mais il contrevient à la convention. Vous pouvez soutenir que le nom log est une sous-convention, je suppose. Mais en général, nommer des constantes en majuscules n'est pas la solution idéale, mais bien la meilleure.

1
andronikus

Ne vivez pas fanatiquement avec les conventions que Sun a préparées, faites-vous ce que vous sentez juste pour vous et votre équipe.

Par exemple, voici comment Eclipse le fait, enfreignant la convention. Essayez d'ajouter implements Serializable et Eclipse demanderont à générer cette ligne pour vous.

Mise à jour: Il y avait des cas spéciaux qui ont été exclus ne le savaient pas. Cependant, je refuse de faire ce que vous et votre équipe semble apte.

0
Farmor