Je vois que Java has Boolean (class) vs boolean (primitive). De même, il y a un Integer (class) vs int (primitive). Quelle est la meilleure pratique pour savoir quand utiliser la version primitive vs Dois-je essentiellement utiliser la version de classe à moins d'avoir une raison (de performance?) spécifique de ne pas le faire? Quelle est la manière la plus courante et acceptée de les utiliser?
Dans le point 5, de Java efficace, Joshua Bloch dit
La leçon est claire: préférez les primitives aux primitives encadrées, et faites attention aux autoboxes involontaires.
Une bonne utilisation des classes consiste à les utiliser en tant que types génériques (y compris les classes Collection, telles que les listes et les cartes) ou lorsque vous souhaitez les transformer en un autre type sans transtypage implicite (par exemple Integer
la classe a des méthodes doubleValue()
ou byteValue()
.
Edit: La raison de Joshua Bloch est:
// Hideously slow program! Can you spot the object creation? public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); }
Ce programme obtient la bonne réponse, mais il est beaucoup plus lent qu'il ne devrait l'être, en raison d'une erreur typographique à un caractère. La variable
sum
est déclarée commeLong
au lieu delong
, ce qui signifie que le programme construit environ 2 ^ 31 instancesLong
inutiles (environ une pour chaque fois que lelong i
est ajouté auLong sum
). Changer la déclaration de somme deLong
àlong
réduit le temps d'exécution de 43 secondes à 6,8 secondes sur ma machine.
La pratique standard consiste à utiliser les primitives, sauf si vous avez affaire à des génériques (assurez-vous que vous êtes au courant de autoboxing & unboxing !).
Il y a plusieurs bonnes raisons de suivre la convention:
1. Vous évitez les erreurs simples:
Il existe des cas subtils et non intuitifs qui surprennent souvent les débutants. Même les codeurs expérimentés se trompent et font parfois ces erreurs (j'espère que cela sera suivi de jurer lorsqu'ils débogueront le code et trouveront l'erreur!).
L'erreur la plus courante consiste à utiliser a == b
Au lieu de a.equals(b)
. Les gens ont l'habitude de faire a == b
Avec des primitives, donc c'est facile à faire lorsque vous utilisez les wrappers Object.
Integer a = new Integer(2);
Integer b = new Integer(2);
if (a == b) { // Should be a.equals(b)
// This never gets executed.
}
Integer c = Integer.valueOf(2);
Integer d = Integer.valueOf(2);
if (c == d) { // Should be a.equals(b), but happens to work with these particular values!
// This will get executed
}
Integer e = 1000;
Integer f = 1000;
if (e == f) { // Should be a.equals(b)
// Whether this gets executed depends on which compiler you use!
}
2. Lisibilité:
Considérez les deux exemples suivants. La plupart des gens diraient que le second est plus lisible.
Integer a = 2;
Integer b = 2;
if (!a.equals(b)) {
// ...
}
int c = 2;
int d = 2;
if (c != d) {
// ...
}
3. Performances:
Le fait est que est plus lent à utiliser les wrappers d'objets pour les primitives qu'à utiliser simplement les primitives. Vous ajoutez le coût de l'instanciation d'objet, des appels de méthode, etc. aux choses que vous utilisez partout.
La citation de "... disons environ 97% du temps: l'optimisation prématurée est la racine de tout mal" la citation ne s'applique pas vraiment ici. Il parlait d'optimisations qui rendent le code (ou le système) plus compliqué - si vous êtes d'accord avec le point # 2, c'est une optimisation qui rend le code moins compliqué!
4. C'est la convention:
Si vous faites des choix stylistiques différents pour 99% des autres programmeurs Java là-bas, il y a 2 inconvénients:
Normalement, j'énumérerais quelques contre-points, mais honnêtement, je ne vois pas de bonnes raisons de ne pas suivre la convention ici!
Habituellement, je vais avec les primitives. Cependant, une particularité d'utiliser des classes comme Integer
et Boolean
est la possibilité d'affecter null
à ces variables. Bien sûr, cela signifie que vous devez faire null
des contrôles tout le temps, mais encore mieux pour obtenir une NullPointerException que d'avoir des erreurs logiques dues à l'utilisation de int
ou boolean
variable qui n'a pas été initialisée correctement.
Bien sûr, puisque Java 8 vous pouvez (et probablement devriez) aller plus loin et au lieu, par exemple, de Integer
, vous pouvez utiliser Optional<Integer>
pour les variables pouvant ou non avoir une valeur.
De plus, il introduit la possibilité d'utiliser null
pour affecter à ces variables un " inconnu " ou " valeur générique ". Cela peut être pratique dans certaines situations, par exemple dans Ternary Logic . Ou vous voudrez peut-être vérifier si un certain objet correspond à un modèle; dans ce cas, vous pouvez utiliser null
pour les variables du modèle qui peuvent avoir n'importe quelle valeur dans l'objet.
Dans les mots du profane:
Vous utilisez les wrappers lorsque vous devez ajouter des éléments à des collections.
Les collections ne peuvent pas contenir de primitives.
Java propose la mise en boîte automatique comme m3th0dman l'a souligné. Pensez au niveau le plus bas possible et vous verrez que la mise en boîte automatique (entrée ou sortie) d'une valeur primitive impliquera des cycles d'horloge passés dans certaines tâches dont vous n'avez pas besoin si vous travaillez avec des types de données natifs autour de votre application.
En règle générale, vous devez essayer d'utiliser des types de données natifs dans la mesure du possible.