Comment bien comparer deux nombres Entiers en Java?
Je sais que si vous comparez un coffret primitif Entier avec une constante telle que:
Integer a = 4;
if (a < 5)
a
sera automatiquement unboxed et la comparaison sera travail.
Cependant, ce qui se passe lorsque vous comparez deux en boîte Integers
et souhaitez comparer les sexes ou supérieur/inférieur?
Integer a = 4;
Integer b = 5;
if (a == b)
Permettra de code ci-dessus résultat de la vérification pour voir si elles sont le même objet, ou d'une auto-unbox dans ce cas?
Ce sujet:
Integer a = 4;
Integer b = 5;
if (a < b)
?
- Eh bien, ce qui s'est passé lorsque vous avez essayé? Qu'avez-vous observer?
- Kiers: explicite de L'expérience ne pouvait réfuter, ne prouve pas que unboxing se produit. Si vous utilisez
==
au lieu deequals
donne le résultat correct, cela peut être parce que la boîte contenant les numéros sont internés ou autrement réutilisés (comme une optimisation du compilateur, sans doute). La raison de poser cette question est de savoir ce qui se passe en interne, et non pas ce qui semble se passer. (Au moins, c'est pourquoi je suis ici.)
Vous devez vous connecter pour publier un commentaire.
Non, == entre Integer, Long, etc. vérifier de référence de l'égalité - c'est à dire
cela permettra de vérifier si
x
ety
reportez-vous à la même objet plutôt que l'égalité des objets.Donc
est garanti pour imprimer
false
. Un stage de "petits" autoboxed valeurs peut conduire à la délicate résultats:Cette impression sera
true
, en raison des règles de la boxe (JLS section 5.1.7). C'est toujours en référence à l'égalité, mais les références véritablement sont égalité.Personnellement j'utiliserais:
ou
Le dernier est un peu moins efficace, il n'y a pas une surcharge pour
Integer.equals(Integer)
alors il aura à faire moment de l'exécution de la vérification de type, tandis que le premier utilise le fait que nous savons déjà que les deux objets sontInteger
s.Heureusement,
compareTo
connaît les types, de sorte que:doit encore être efficace. Bien sûr, c'est de la micro-optimisation territoire et vous devez utiliser le code que vous trouverez la plus claire, après s'être assurer qu'il est correct 🙂
Comme vous le dites, pour toute comparaison entre un wrapper type (
Integer
,Long
etc) et un type numérique (int
,long
etc) de l'emballage du type de valeur est unboxed et le test est appliqué à la primitive valeurs impliquées.Cela se produit dans le cadre de l'option binaire numérique de promotion (JLS section 5.6.2). Considérer chaque individu documentation de l'exploitant pour voir si elle est appliquée. Par exemple, à partir de la documentation pour
==
et!=
(JLS 15.21.1):et pour
<
,<=
,>
et>=
(JLS 15.20.1)Remarque comment aucun de ce qui est considéré comme une partie de la situation où ni type est un type numérique.
x.compareTo(y) < 0
au lieu dex < y
?==
sera toujours l'objet de test de l'égalité. Il est facile de se laisser berner, cependant:Vos exemples avec les inégalités de travail, car ils ne sont pas définis sur les Objets. Cependant, avec la
==
comparaison, l'objet, l'égalité sera toujours vérifiée. Dans ce cas, lorsque vous initialisez les objets à partir d'une boîte primitif, le même objet est utilisé (pour a et b). C'est un bon d'optimisation depuis la primitive de la boîte de classes sont immuables.200
, à la fois des tests d'impressionfalse
.equals
être appelé".Ctrl+3
et de recherche pourSyntax coloring
.Integer c = Integer.valueOf(10); Integer d = Integer.valueOf(10); System.out.println(c == d); //prints TRUE
Parce que valueOf utilise un cach de -127 à +127. Comme pour Longtemps.valueOf. Donc, ne comptez pas sur == sauf pour des Primitifs ou EnumDepuis Java 1.7, vous pouvez utiliser Objets.est égal à:
==
vérifie la référence à l'égalité, cependant lors de l'écriture d'un code comme:Java est assez intelligent pour réutiliser le même immuable pour
a
etb
, donc, c'est vrai:a == b
. Curieux, j'ai écrit un petit exemple pour montrer où java s'arrête l'optimisation de cette façon:Quand j'ai compiler et exécuter ce (sur ma machine), j'obtiens:
Appel
Fonctionne la plupart du temps, mais il n'est pas garanti pour toujours, donc ne l'utilisez pas.
La plus appropriée pour comparer deux Entiers des classes pour l'égalité, en supposant qu'ils sont appelés 'a' et 'b' est l'appel de:
Vous pouvez également utiliser ce moyen qui est légèrement plus rapide.
Sur ma machine 99 milliards d'opérations ont eu 47 secondes à l'aide de la première méthode, et 46 secondes à l'aide de la seconde méthode. Vous devez être en le comparant des milliards de valeurs de voir la différence.
Note que " a " peut être nulle puisque c'est un Objet. La comparaison de cette façon à ne pas provoquer une exception de pointeur null.
Pour comparer des plus et des moins, utiliser
if (a==b)
ne fonctionne que pour les petites valeurs et ne fonctionne pas la plupart du temps.tl;dr mon avis est d'utiliser un unaire
+
pour déclencher l'unboxing sur l'un des opérandes lors de la vérification de la valeur de l'égalité, et il suffit d'utiliser les opérateurs mathématiques autrement. Justification suit:Il a été déjà mentionné que
==
comparaison pourInteger
est l'identité de la comparaison, qui n'est généralement pas ce qu'est un programmeur voulez, et que le but est de faire la comparaison de la valeur; encore, j'ai fait un peu de science sur la façon de faire la comparaison la plus efficace, à la fois en terme de code de la compacité, de la justesse et de la vitesse.J'ai utilisé l'habitude tas de méthodes:
et a obtenu ce code après la compilation et la décompilation:
Comme vous pouvez le voir facilement, la méthode 1 appels
Integer.equals()
(évidemment), les méthodes 2-4 résultat dans exactement le même code, en dépliant les valeurs par le biais de.intValue()
et ensuite de les comparer directement, et la méthode 5 juste déclenche une identité de comparaison, à cause d'une mauvaise façon de comparer les valeurs.Depuis (comme déjà mentionné, par exemple en JS)
equals()
occasionne des frais généraux (qu'il a à faireinstanceof
et incontrôlées cast), les méthodes 2-4 travaillera avec exactement la même vitesse, noticingly mieux que la méthode 1 lorsque utilisé dans les boucles serrées, depuis HotSpot n'est pas susceptible d'optimiser les jette &instanceof
.C'est assez similaire avec d'autres opérateurs de comparaison (par exemple,
<
/>
) - ils vont déclencher des unboxing, tout en utilisantcompareTo()
ne veut pas le faire, mais cette fois, l'opération est très optimisable par HS depuisintValue()
est juste une méthode de lecture (le premier candidat à être optimisé out).À mon avis, le rarement utilisé la version 4 est la plus concise - tout assaisonné C/développeur Java sait que unaire plus est, dans la plupart des cas égale à jeter à
int
/.intValue()
- si c'est peut-être un peu WTF moment pour certains (surtout ceux qui n'ont pas utilisé unaire plus au cours de leur vie), il montre sans doute le but le plus clairement et le plus sèchement - il montre que nous voulons unint
valeur de l'un des opérandes, forçant les autres de la valeur à unbox ainsi. C'est aussi, incontestablement, le plus semblable à la régulièrei1 == i2
comparaison utilisée pour des primitifsint
valeurs.Mon vote va pour
i1 == +i2
&i1 > i2
style pourInteger
objets, à la fois pour la performance & des raisons de cohérence. Il fait également le code portable de primitives sans rien changer d'autre que la déclaration de type. À l'aide de méthodes appelées semble que l'introduction de la sémantique de bruit pour moi, semblable à la très critiquéebigInt.add(10).multiply(-3)
style.unary +
(unaire plus), voir par exemple stackoverflow.com/questions/2624410/...Dans mon cas, je devais comparer les deux
Integer
s pour l'égalité, où les deux d'entre eux pourraient êtrenull
. Recherché sujet similaire, n'a pas trouvé quelque chose élégante pour cette. Est venu avec un simple utilitaire de fonctions.cette méthode permet de comparer deux Entiers avec null vérifier, voir les tests
Objects.equals(x,y)
méthode au lieu de rouler votre propre.