web-dev-qa-db-fra.com

Comment présenter le type primitif nullable int en Java?

Je conçois une classe d'entité qui a un champ nommé "documentYear", qui peut contenir des valeurs entières non signées telles que 1999, 2006, etc. Ce champ peut également être "inconnu", c'est-à-dire ne pas savoir en quelle année le document créé.

Par conséquent, un type int nullable comme en C # conviendra bien. Cependant, Java n'a pas de fonctionnalité Nullable comme C #. 

J'ai deux options mais je ne les aime pas toutes les deux:

  1. Utilisez Java.lang.Integer au lieu du type primitif int;
  2. Utilisez -1 pour présenter la valeur "inconnue"

Quelqu'un a-t-il de meilleures options ou idées? 

Update : Ma classe d'entités aura des dizaines de milliers d'instances. par conséquent, les frais généraux de Java.lang.Integer sont peut-être trop importants pour les performances globales du système.

32
yinyueyouge

Vous devrez soit abandonner le type primitif, soit utiliser une valeur int arbitraire comme "année non valide".

Une valeur négative est en fait un bon choix car il y a peu de chance d'avoir une année valide qui causerait un dépassement d'entier et il n'y a pas d'année négative valide.

27
hhafez

En utilisant la classe Integer, voici probablement ce que vous voulez faire. La surcharge associée à l'objet est très probablement (mais pas nécessairement) triviale pour la réactivité et les performances globales de vos applications.

32
Matthew Vines

Des dizaines de milliers d'instances d'Integer, ce n'est pas beaucoup. Considérez dépenser quelques centaines de kilo-octets plutôt que d’optimiser prématurément. C'est un petit prix à payer pour l'exactitude.

Méfiez-vous des valeurs sentinelles telles que null ou 0. Cela revient fondamentalement à mentir, puisque 0 n'est pas une année et que null n'est pas un entier. Une source commune de bogues, surtout si vous n'êtes pas le seul responsable du logiciel à un moment donné.

Pensez à utiliser une valeur de type null telle que Option, parfois appelée Maybe. Populaire dans des langues telles que Scala et Haskell, cela ressemble à un conteneur qui ne contient qu'un ou zéro éléments. Votre champ aurait le type Option<Integer>, ce qui annoncerait la nature facultative de votre champ d'année au système de types et obligerait tout autre code à traiter les années éventuellement manquantes.

Voici une bibliothèque qui inclut le type Option.

Voici comment appeler votre code si vous l'utilisiez:

partyLikeIts.setDocumentYear(Option.some(1999));

Option<Integer> y = doc.getDocumentYear();
if (y.isSome())
   // This doc has a year
else
   // This doc has no year

for (Integer year: y) {
  // This code only executed if the document has a year.
}
15
Apocalisp

Une autre option consiste à associer un indicateur boolean qui indique si votre valeur d'année est valide ou non. Ce drapeau étant false signifierait que l'année est "inconnue". Cela signifie que vous devez vérifier une primitive (booléen) pour savoir si vous avez une valeur, et si vous en avez une, vérifier une autre primitive (entier).

Les valeurs sentinelles aboutissent souvent à un code fragile. Il est donc intéressant de faire un effort pour éviter la valeur sentinelle, à moins que vous ne soyez vraiment sûr que cela ne sera jamais un cas d'utilisation.

2
Eddie

Vous pouvez utiliser un int régulier, mais utilisez une valeur telle que Integer.MAX_VALUE ou Integer.MIN_VALUE, qui sont des constantes définies comme date invalide. Il est également plus évident que -1 ou une valeur négative faible soit invalide. Cela ne ressemblera certainement pas à une date à 4 chiffres que nous avons l'habitude de voir.

1
Kekoa

Pour être complet, une autre option (certainement pas la plus efficace) consiste à utiliser une classe d'encapsulation Year.

class Year {
    public int year;
    public Year(int year) { this.year = year; }
}

Year documentYear = null;
documentYear = new Year(2013);

Ou, si elle est plus sémantique ou si vous souhaitez plusieurs types d’entiers nullables (autres que Years), vous pouvez imiter les primitives C # Nullable comme suit:

class Int {
    public int value;
    public Int(int value) { this.value = value; }
    @Override 
    public String toString() { return value; }
}
1
azz

L'utilisation de la primitive int et du type Integer est un exemple parfait d'optimisation prématurée.

Si vous faites le calcul:

  • int = N (4)
  • Entier = N (16)

Donc, pour 10 000 ints, il vous en coûtera 40 000 octets ou 40 000 kt. Cela coûte 160 000 octets ou 160 000 euros pour 10 000 ints. Si vous considérez la quantité de mémoire requise pour traiter les images/photos/vidéos, les données sont pratiquement négligeables.

Je suggère de cesser de perdre du temps prématurément en optimisant en fonction des types de variables et de rechercher une bonne structure de données qui facilitera le traitement de toutes ces données. Quoi que vous fassiez, sauf si vous définissez des variables primitives 10K individuellement, cela finira de toute façon sur le tas.

1
Evan Plaice

Si vous avez un entier et que vous craignez de confondre une valeur arbitraire pour null avec une valeur réelle, vous pouvez utiliser long à la place. C'est plus efficace que d'utiliser un entier et Long.MIN_VALUE n'est nulle part près d'une valeur int valide.

1
Peter Lawrey

Java.lang.Integer est raisonnable dans ce cas. Et il a déjà implémenté Serializable, de sorte que vous ne pouvez enregistrer que le champ Année sur le disque dur et le charger.

0
Truong Ha

Une autre option pourrait consister à utiliser une valeur spéciale en interne (-1 ou Integer.MIN_VALUE ou similaire), mais d'exposer le nombre entier sous deux méthodes:

hasValue() {
    return (internalValue != -1);
}

getValue() {
    if (internalValue == -1) {
        throw new IllegalStateException(
            "Check hasValue() before calling getValue().");
    }
    return internalValue;
}
0
MB.

Quel est le problème avec Java.lang.Integer? C'est une solution raisonnable, sauf si vous stockez de très grandes quantités de cette valeur.

Si vous voulez utiliser des primitives, une valeur -1 serait également une bonne solution. La seule autre option que vous avez est d'utiliser un drapeau booléen distinct, comme quelqu'un l'a déjà suggéré. Choisissez votre poison :)

PS: merde, j'essayais de me tirer d'un petit mensonge blanc sur les objets vs les structures. Mon point était qu'il utilise plus de mémoire, similaire à la méthode boolean flag, bien que syntaxiquement le type nullable soit plus agréable bien sûr. De plus, je n'étais pas sûr que quelqu'un ayant une expérience en Java saurait ce que je voulais dire par struct.

0
Thorarin

Si vous voulez économiser de la mémoire, je vous conseillerais de conserver plusieurs années dans une seule variable int. Ainsi, 0 est nil. Ensuite, vous pouvez faire des hypothèses afin d'optimiser. Si vous travaillez uniquement avec les dates actuelles, comme les années 1970 à 2014, vous pouvez soustraire 1969 à chacune d’elles et entrer dans la plage 1—55. De telles valeurs peuvent être codées avec seulement 6 bits. Ainsi, vous pouvez diviser votre int qui est toujours 32 bits, en 4 zones, avec une année. De cette façon, vous pouvez placer 4 années dans la plage 1970-2226 dans une seule variable int. Plus votre plage est étroite, comme entre 2000 et 2014 (4 bits), plus vous pouvez accumuler d'années dans une seule variable int.

0
Aleks N.

Vous pouvez utiliser l'annotation @Nullable si vous utilisez Java 7.

0
user3231931