web-dev-qa-db-fra.com

Quand utiliser la classe primitive vs en Java?

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?

56
Casey Patton

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 comme Long au lieu de long, ce qui signifie que le programme construit environ 2 ^ 31 instances Long inutiles (environ une pour chaque fois que le long i est ajouté au Long sum). Changer la déclaration de somme de Long à long réduit le temps d'exécution de 43 secondes à 6,8 secondes sur ma machine.

49
m3th0dman

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:

  • Vous trouverez le code des autres plus difficile à lire. 99% des exemples/tutoriels/etc utiliseront des primitives. Chaque fois que vous en lirez un, vous aurez la surcharge cognitive supplémentaire de penser à quoi il ressemblerait dans le style auquel vous êtes habitué.
  • D'autres personnes trouveront votre code plus difficile à lire. Chaque fois que vous posez des questions sur Stack Overflow, vous devrez parcourir les réponses/commentaires demandant "pourquoi n'utilisez-vous pas de primitives?". Si vous ne me croyez pas, regardez les batailles que les gens ont sur des choses comme le placement des supports, qui n'affecte même pas le code généré!

Normalement, j'énumérerais quelques contre-points, mais honnêtement, je ne vois pas de bonnes raisons de ne pas suivre la convention ici!

30
vaughandroid

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.

12
tobias_k

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.

2
Tulains Córdova

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.

0
Silvarion