Pendant la phase de développement, certaines variables doivent être corrigées dans le même cycle, mais peuvent devoir être modifiées au fil du temps. Par exemple, boolean
pour signaler le mode de débogage, nous faisons donc des choses dans le programme que nous ne ferions pas normalement.
Est-ce un mauvais style de contenir ces valeurs dans une constante, c'est- final static int CONSTANT = 0
à- dire en Java? Je sais qu'une constante reste la même pendant l'exécution, mais est-elle également censée être la même pendant tout le développement, sauf pour les changements imprévus, bien sûr?
J'ai cherché des questions similaires, mais je n'ai rien trouvé qui correspondait exactement à la mienne.
final
vous donne une garantie imposée par le compilateur que le programme ne modifiera pas la valeur. Je ne m'en passerais pas juste parce que le programmeur pourrait vouloir modifier la valeur attribuée dans le code source.gravity
de partie / en cours de partie. Ils ne signifient pas nécessairement,gravity
c'est la même chose sur toutes les planètes ... Cela dit, la solution saine est de fairegravity
une constante, mais de la retirer d'unplanet
fichier ou d'une base de données au début du périmètre concerné.Réponses:
En Java, les constantes finales statiques peuvent être copiées, par le compilateur, comme leurs valeurs, dans le code qui les utilise . Par conséquent, si vous publiez une nouvelle version de votre code et qu'il existe une dépendance en aval qui a utilisé la constante, la constante de ce code ne sera pas mise à jour à moins que le code en aval ne soit recompilé. Cela peut être un problème s'ils utilisent ensuite cette constante avec du code qui attend la nouvelle valeur, car même si le code source est correct, le code binaire ne l'est pas.
C'est une verrue dans la conception de Java, car c'est l'un des très rares cas (peut-être le seul cas) où la compatibilité source et la compatibilité binaire ne sont pas les mêmes. À l'exception de ce cas, vous pouvez échanger une dépendance avec une nouvelle version compatible API sans que les utilisateurs de la dépendance n'aient à recompiler. De toute évidence, cela est extrêmement important compte tenu de la manière dont les dépendances Java sont généralement gérées.
Pour aggraver les choses, le code ne fera que silencieusement la mauvaise chose plutôt que de produire des erreurs utiles. Si vous deviez remplacer une dépendance par une version avec des définitions de classe ou de méthode incompatibles, vous obtiendriez des erreurs de chargeur de classe ou d'invocation, qui fourniraient au moins de bons indices sur le problème. À moins que vous n'ayez modifié le type de la valeur, ce problème apparaîtra simplement comme une inconduite d'exécution mystérieuse.
Plus ennuyeux est que les JVM d'aujourd'hui pourraient facilement aligner toutes les constantes au moment de l'exécution sans pénalité de performance (autre que la nécessité de charger la classe définissant la constante, qui est probablement chargée de toute façon), malheureusement la sémantique du langage date des jours précédant les JIT . Et ils ne peuvent pas changer la langue car le code compilé avec les compilateurs précédents ne sera pas correct. La compatibilité avec les bogues recommence.
À cause de tout cela, certaines personnes conseillent de ne jamais changer du tout une valeur finale statique. Pour les bibliothèques qui pourraient être largement distribuées et mises à jour de manière inconnue à des moments inconnus, c'est une bonne pratique.
Dans votre propre code, en particulier au sommet de la hiérarchie des dépendances, vous vous en sortirez probablement. Mais dans ces cas, déterminez si vous avez vraiment besoin que la constante soit publique (ou protégée). Si la constante ne concerne que la visibilité du package, il est raisonnable, selon vos circonstances et les normes de code, que le package entier soit toujours recompilé en même temps, et le problème disparaît ensuite. Si la constante est privée, vous n'avez aucun problème et pouvez la changer quand vous le souhaitez.
la source
Tout élément de votre code source, y compris
const
les constantes globales déclarées, peut être sujet à changement avec une nouvelle version de votre logiciel.Les mots clés
const
(oufinal
en Java) sont là pour signaler au compilateur que cette variable ne changera pas pendant l'exécution de cette instance du programme . Rien de plus. Si vous voulez envoyer des messages au responsable suivant, utilisez un commentaire dans la source, c'est pour ça qu'ils sont là.Est une meilleure façon de communiquer avec votre futur.
la source
TaxRate
l'êtrepublic
me rend nerveux. Je voudrais savoir avec certitude que seul le service commercial est impacté par ce changement et pas aussi nos fournisseurs qui nous facturent une taxe. Qui sait ce qui s'est passé dans la base de code depuis que ce commentaire a été écrit.public const
champs doivent uniquement être utilisés pour des choses qui ne changent jamais de jamais, comme Math.pi. Si vous créez une bibliothèque, les choses qui pourraient changer pendant le développement ou avec une nouvelle version devraient l'êtrepublic static readonly
, afin de ne pas causer de problèmes avec les utilisateurs de votre bibliothèque.Nous devons distinguer deux aspects des constantes:
Et puis il y a un troisième type connexe: les variables dont la valeur ne change pas, c'est-à-dire les noms d'une valeur. La différence entre une de ces variables immuables et une constante est lorsque la valeur est déterminée / affectée / initialisée: une variable est initialisée au moment de l'exécution, mais la valeur d'une constante est connue pendant le développement. Cette distinction est un peu confuse car une valeur peut être connue pendant le développement mais n'est en fait créée que lors de l'initialisation.
Mais si la valeur d'une constante est connue au moment de la compilation, le compilateur peut effectuer des calculs avec cette valeur. Par exemple, le langage Java a le concept d' expressions constantes . Une expression constante est toute expression qui se compose uniquement de littéraux de primitives ou de chaînes, d'opérations sur des expressions constantes (telles que la conversion, l'addition, la concaténation de chaînes) et de variables constantes. [ JLS §15.28 ] Une variable constante est une
final
variable qui est initialisée avec une expression constante. [JLS §4.12.4] Donc pour Java, c'est une constante de temps de compilation:Cela devient intéressant lorsqu'une variable constante est utilisée dans plusieurs unités de compilation, puis la déclaration est modifiée. Considérer:
A.java
:B.java
:Maintenant, lorsque nous compilons ces fichiers, le
B.class
bytecode déclarera un champY = 9
car ilB.Y
s'agit d'une variable constante.Mais lorsque nous changeons la
A.X
variable en une valeur différente (disonsX = 0
) et recompilons uniquement leA.java
fichier, nous nous référonsB.Y
toujours à l'ancienne valeur. Cet étatA.X = 0, B.Y = 9
est incompatible avec les déclarations du code source. Bon débogage!Cela ne signifie pas que les constantes ne doivent jamais être modifiées. Les constantes sont définitivement meilleures que les nombres magiques qui apparaissent sans explication dans le code source. Cependant, la valeur des constantes publiques fait partie de votre API publique . Cela n'est pas spécifique à Java, mais se produit également en C ++ et dans d'autres langages qui comportent des unités de compilation distinctes. Si vous modifiez ces valeurs, vous devrez recompiler tout le code dépendant, c'est-à-dire effectuer une compilation propre.
Selon la nature des constantes, elles peuvent avoir conduit à des hypothèses incorrectes de la part des développeurs. Si ces valeurs sont modifiées, elles peuvent déclencher un bogue. Par exemple, un ensemble de constantes peut être choisi de manière à former certaines configurations binaires, par exemple
public static final int R = 4, W = 2, X = 1
. Si ceux-ci sont modifiés pour former une structure différente commeR = 0, W = 1, X = 2
alors le code existant tel queboolean canRead = perms & R
devient incorrect. Et pensez au plaisir qui allait en résulterInteger.MAX_VALUE
! Il n'y a pas de solution ici, il est juste important de se rappeler que la valeur de certaines constantes est vraiment importante et ne peut pas être modifiée simplement.Mais pour la majorité des constantes, les modifier va bien se passer tant que les restrictions ci-dessus sont prises en compte. Une constante est sûre de changer lorsque la signification, et non la valeur spécifique, est importante. C'est par exemple le cas pour des paramètres tels que
BORDER_WIDTH = 2
ouTIMEOUT = 60; // seconds
ou des modèles tels queAPI_ENDPOINT = "https://api.example.com/v2/"
- bien que certains ou tous devraient être spécifiés dans les fichiers de configuration plutôt que dans le code.la source
Une constante n'est garantie que pour la durée de vie de l'application . Tant que cela est vrai, il n'y a aucune raison de ne pas profiter de la fonction de langue. Vous avez juste besoin de savoir quelles sont les conséquences de l'utilisation d'une constante par rapport aux indicateurs du compilateur dans le même but:
Après avoir maintenu une application qui activerait le dessin de boîtes englobantes pour les formes afin que nous puissions déboguer la façon dont elles ont été dessinées, nous avons rencontré un problème. Après la refactorisation, tout le code qui a été désactivé par les drapeaux du compilateur ne se compilait pas. Après cela, nous avons intentionnellement changé nos indicateurs de compilateur en constantes d'application.
Je dis cela pour démontrer qu'il y a des compromis. Le poids de quelques booléens n'allait pas faire manquer de mémoire à l'application ni prendre trop de place. Cela pourrait ne pas être vrai si votre constante est vraiment un grand objet qui a essentiellement une poignée pour tout dans votre code. S'il ne prend pas soin de supprimer toutes les références qu'il détient à un objet après qu'il ne soit plus nécessaire, votre objet peut être la source d'une fuite de mémoire.
Je ne suis pas fan des simples déclarations générales, mais en général, votre collègue senior a raison. Si quelque chose est appelé à changer souvent, il peut être nécessaire que ce soit un élément configurable. Par exemple, vous pourriez probablement convaincre votre collègue pour une constante
IsInDebugMode = true
lorsque vous souhaitez protéger du code contre la rupture. Cependant, certaines choses peuvent devoir changer plus souvent que vous ne publiez une application. Si tel est le cas, vous avez besoin d'un moyen de modifier cette valeur au moment approprié. Vous pouvez prendre l'exemple d'unTaxRate = .065
. Cela peut être vrai au moment où vous compilez votre code, mais en raison de nouvelles lois, il peut changer avant de publier la prochaine version de votre application. C'est quelque chose qui doit être mis à jour à partir d'un mécanisme de stockage (comme un fichier ou une base de données)la source
#ifdef
s? Comme ceux-ci sont basés sur la substitution textuelle du code source, ils ne font pas partie de la sémantique du langage de programmation. Notez que Java n'a pas de préprocesseur.#ifdef
drapeaux. Bien qu'ils ne fassent pas partie de la sémantique de C, ils font partie de C #. J'écrivais pour le contexte plus large de l'agnosticisme linguistique.Le
const
,#define
oufinal
est un indice du compilateur (notez que le#define
n'est pas réellement un indice, c'est une macro et nettement plus puissant). Il indique que la valeur ne changera pas au cours de l'exécution d'un programme et diverses optimisations peuvent être effectuées.Cependant, en tant qu'indicateur de compilation, le compilateur fait des choses qui ne sont pas toujours attendues par le programmeur. En particulier, javac insérera un
static final int FOO = 42;
afin que, partout où ilFOO
est utilisé, le code d'octets compilé réel soit lu42
.Ce n'est pas une grande surprise jusqu'à ce que quelqu'un modifie la valeur sans recompiler l'autre unité de compilation (fichier .java) - et le
42
reste dans le code d'octet (voir est-il possible de désactiver l'inclusion de javac dans les variables finales statiques? ).Faire quelque chose
static final
signifie que c'est cela et que ce sera toujours plus et le changer est vraiment une grosse affaire - surtout si c'est autre choseprivate
.Les constantes pour des choses comme ce
final static int ZERO = 0
n'est pas un problème.final static double TAX_RATE = 0.55
(en plus d'être de l'argent et du double, c'est mauvais et devrait utiliser BigDecimal, mais ce n'est pas une primitive et donc pas en ligne) est un problème et doit être examiné avec grand soin pour savoir où il est utilisé.la source
is a problem and should be examined with great care for where it is used.
Pourquoi est-ce un problème?Comme son nom l'indique, les constantes ne doivent pas changer pendant l'exécution et à mon avis, les constantes sont définies pour ne pas changer à long terme (vous pouvez consulter cette question SO pour plus d'informations.
En ce qui concerne le besoin d'indicateurs (par exemple pour le mode de développement), vous devez plutôt utiliser un fichier de configuration ou un paramètre de démarrage (de nombreux IDE prennent en charge la configuration du paramètre de démarrage sur une base par projet; reportez-vous à la documentation appropriée) pour activer ce mode - De cette façon, vous gardez la flexibilité d'utiliser un tel mode et vous ne pouvez pas oublier de le changer chaque fois que le code devient productif.
la source
Pouvoir être modifié entre les exécutions est l'un des points les plus importants pour définir une constante dans votre code source!
La constante vous donne un emplacement bien défini et documenté (dans un sens) pour changer la valeur chaque fois que vous en avez besoin pendant la durée de vie de votre code source. C'est aussi une promesse que changer la constante à cet endroit changera en fait toutes les occurrences de ce qu'elle représente.
À titre d'exemple défavorable: il ne serait pas logique d'avoir une constante
TRUE
qui s'évaluetrue
dans une langue qui a réellement letrue
mot - clé. Vous ne diriez jamais, jamais, pas même une seule fois,TRUE=false
sauf comme une plaisanterie cruelle.Bien sûr, il existe d'autres utilisations des constantes, par exemple raccourcir le code (
CO_NAME = 'My Great World Unique ACME Company'
), éviter la duplication (PI=3.141
), définir des conventions (TRUE=1
) ou autre chose, mais avoir une position définie pour modifier la constante est certainement l'une des plus importantes.la source