Как сравнить два числа в java

от admin

Как правильно сравнить два целых числа в Java?

Я знаю, что если вы сравниваете примитивный Integer с коротким номером с константой, такой как:

a автоматически будет распакован, и сравнение будет работать.

Однако, что происходит, когда вы сравниваете два вставных Integers и хотите сравнить либо равенство, либо меньше/больше, чем?

Будет ли выше код приводить к проверке того, являются ли они одним и тем же объектом, или будет ли он автоматически распаковываться в этом случае?

7 ответов

Нет, == между Integer, Long и т.д. будет проверять ссылочное равенство — i.e.

это проверит, относятся ли теги x и y к одному и тому же объекту, а не к равным объектам.

гарантируется печать false . Интернирование «малых» значений автобокса может привести к сложным результатам:

Это напечатает true , из-за правил бокса (JLS раздел 5.1.7). Он по-прежнему ссылается на равенство, но ссылки действительно равны.

Лично я бы использовал:

Последнее немного менее эффективно — нет перегрузки для Integer.equals(Integer) , поэтому ему придется выполнять проверку типа времени выполнения, тогда как первый использует тот факт, что мы уже знаем, что оба объекта Integer s.

К счастью, compareTo знает о типах, поэтому:

должен быть эффективен. Конечно, это область микрооптимизации, и вы должны использовать код, который вы найдете наиболее ясным — после того, как он будет прав:)

Как вы говорите, для любого сравнения между типом-оболочкой ( Integer , Long и т.д.) и числовым типом ( int , Long и т.д.) значение типа обертки распаковывается, и тест применяется к примитивные значения.

Это происходит как часть двоичной цифровой рекламы (JLS раздел 5.6.2). Посмотрите на каждую отдельную документацию оператора, чтобы узнать, применяется ли она. Например, из документов для == и!= (JLS 15.21.1):

Если операнды равенства оператор имеют как числовой тип, так и один имеет числовой тип, а другой является конвертируемой (п. 5.1.8) в числовой тип, двоичное числовое продвижение выполняются над операндами (§5.6.2).

Тип каждого из операндов оператор численного сравнения должен быть тип, который является конвертируемым (п. 5.1.8), к примитивный числовой тип или ошибка компиляции. двоичный числовое продвижение выполняется на операндов (§5.6.2). Если продвинутый тип операндов int или long, то целочисленное сравнение со знаком выполнено; если этот продвинутый тип float или double, затем с плавающей запятой сравнение выполняется.

Обратите внимание, что это не рассматривается как часть ситуации, когда ни один из типов не является числовым.

== все равно будет проверять равномерность объекта. Однако легко обмануть:

Ваши примеры с неравенствами будут работать, поскольку они не определены в объектах. Однако при сравнении == все равно будет проверяться равенство. В этом случае, когда вы инициализируете объекты из примитива в штучной упаковке, используется тот же объект (для a и b). Это хорошая оптимизация, поскольку примитивные классы ящиков неизменяемы.

== проверяет ссылочное равенство, однако при написании кода вроде:

Java достаточно умен, чтобы использовать одно и то же неизменяемое для a и b , поэтому это верно: a == b . Любопытно, что я написал небольшой пример, показывающий, где java останавливает оптимизацию таким образом:

Когда я компилирую и запускаю это (на моей машине), я получаю:

Начиная с Java 1.7 вы можете использовать Objects.equals:

Возвращает true, если аргументы равны друг другу, а false — в противном случае. Следовательно, если оба аргумента равны null, возвращается true, и если только один аргумент имеет значение null, возвращается false. В противном случае равенство определяется с помощью метода equals первого аргумента.

Будет работать большую часть времени, но он не гарантирует, что он всегда будет работать, поэтому не используйте его.

Самый правильный способ сравнения двух классов Integer для равенства, считая, что они называются ‘a’ и ‘b’, это вызвать:

Вы также можете использовать этот способ, который немного быстрее.

На моей машине 99 миллиардов операций заняли 47 секунд, используя первый метод, и 46 секунд, используя второй метод. Вам нужно будет сравнивать миллиарды значений, чтобы увидеть разницу.

Обратите внимание, что ‘a’ может быть null, так как это объект. Сравнение таким образом не приведет к исключению нулевого указателя.

Для сравнения большего и меньшего, используйте

tl; dr Мое мнение заключается в использовании унарного + для запуска unboxing на одном из операндов при проверке равенства значений и просто использовании операторов математики в противном случае. Обоснование следует:

Уже упоминалось, что сравнение == для Integer — это сравнение идентичности, которое обычно не то, что хочет программист, и что целью является сравнение значений; Тем не менее, я сделал небольшую науку о том, как сделать это сравнение наиболее эффективно, как с точки зрения компактности, правильности и скорости кода.

Я использовал обычный набор методов:

и получил этот код после компиляции и декомпиляции:

Как вы можете легко видеть, метод 1 вызывает Integer.equals() (очевидно), методы 2-4 приводят к точному же коду, разворачивая значения с помощью .intValue() , а затем сравнивая их напрямую, а метод 5 просто запускает сравнение идентичности, являющееся неправильным способом сравнения значений.

Поскольку (как уже упоминалось, например, JS) equals() берет накладные расходы (он должен делать instanceof и неконтролируемый отбор), методы 2-4 будут работать с точно такой же скоростью, заметно лучше, чем метод 1, когда используется в жестких петлях, поскольку HotSpot вряд ли оптимизирует отливки и instanceof .

Это очень похоже на другие операторы сравнения (например, < / > ) — они вызовут unboxing, а использование compareTo() не будет — но на этот раз операция очень оптимизирована HS, поскольку intValue() это просто метод геттера (основной кандидат на оптимизацию).

По-моему, редко используемая версия 4 является наиболее кратким способом — каждый опытный разработчик C/Java знает, что унарный плюс в большинстве случаев равен ставке int / .intValue() — хотя это может быть немного Время WTF для некоторых (в основном тех, кто не использовал унарный плюс в своей жизни), он, возможно, показывает намерение наиболее четко и наименее — он показывает, что мы хотим иметь значение int одного из операндов, заставляя другое значение для удаления. Также неоспоримо наиболее похоже на обычные i1 == i2 сравнения используются для примитивного int значения.

How can I properly compare two Integers in Java?

I know that if you compare a boxed primitive Integer with a constant such as:

a will automatically be unboxed and the comparison will work.

However, what happens when you are comparing two boxed Integers and want to compare either equality or less than/greater than?

Will the above code result in checking to see if they are the same object, or will it auto-unbox in that case?

10 Answers 10

No, == between Integer, Long etc will check for reference equality — i.e.

this will check whether x and y refer to the same object rather than equal objects.

Читать:
Как найти простые числа с

is guaranteed to print false . Interning of «small» autoboxed values can lead to tricky results:

This will print true , due to the rules of boxing (JLS section 5.1.7). It’s still reference equality being used, but the references genuinely are equal.

If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between ‘\u0000’ and ‘\u007f’ inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.

Personally I’d use:

As you say, for any comparison between a wrapper type ( Integer , Long etc) and a numeric type ( int , long etc) the wrapper type value is unboxed and the test is applied to the primitive values involved.

This occurs as part of binary numeric promotion (JLS section 5.6.2). Look at each individual operator’s documentation to see whether it’s applied. For example, from the docs for == and != (JLS 15.21.1):

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).

The type of each of the operands of a numerical comparison operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs. Binary numeric promotion is performed on the operands (§5.6.2). If the promoted type of the operands is int or long, then signed integer comparison is performed; if this promoted type is float or double, then floating-point comparison is performed.

Note how none of this is considered as part of the situation where neither type is a numeric type.

== will still test object equality. It is easy to be fooled, however:

Your examples with inequalities will work since they are not defined on Objects. However, with the == comparison, object equality will still be checked. In this case, when you initialize the objects from a boxed primitive, the same object is used (for both a and b). This is an okay optimization since the primitive box classes are immutable.

Since Java 1.7 you can use Objects.equals:

Returns true if the arguments are equal to each other and false otherwise. Consequently, if both arguments are null, true is returned and if exactly one argument is null, false is returned. Otherwise, equality is determined by using the equals method of the first argument.

We should always go for the equals() method for comparison of two integers. It’s the recommended practice.

If we compare two integers using == that would work for certain range of integer values (Integer from -128 to 127) due to the JVM’s internal optimisation.

Please see examples:

Case 1:

In above case JVM uses value of a and b from cached pool and return the same object instance(therefore memory address) of integer object and we get both are equal.Its an optimisation JVM does for certain range values.

Case 2: In this case, a and b are not equal because it does not come with the range from -128 to 127.

Peter Mortensen's user avatar

Siyaram Malav's user avatar

tl;dr my opinion is to use a unary + to trigger the unboxing on one of the operands when checking for value equality, and simply use the maths operators otherwise. Rationale follows:

It has been mentioned already that == comparison for Integer is identity comparison, which is usually not what a programmer want, and that the aim is to do value comparison; still, I’ve done a little science about how to do that comparison most efficiently, both in term of code compactness, correctness and speed.

I used the usual bunch of methods:

and got this code after compilation and decompilation:

As you can easily see, method 1 calls Integer.equals() (obviously), methods 2-4 result in exactly the same code, unwrapping the values by means of .intValue() and then comparing them directly, and method 5 just triggers an identity comparison, being the incorrect way to compare values.

Since (as already mentioned by e.g. JS) equals() incurs an overhead (it has to do instanceof and an unchecked cast), methods 2-4 will work with exactly the same speed, noticingly better than method 1 when used in tight loops, since HotSpot is not likely to optimize out the casts & instanceof .

It’s quite similar with other comparison operators (e.g. < / > ) — they will trigger unboxing, while using compareTo() won’t — but this time, the operation is highly optimizable by HS since intValue() is just a getter method (prime candidate to being optimized out).

In my opinion, the seldom used version 4 is the most concise way — every seasoned C/Java developer knows that unary plus is in most cases equal to cast to int / .intValue() — while it may be a little WTF moment for some (mostly those who didn’t use unary plus in their lifetime), it arguably shows the intent most clearly and most tersely — it shows that we want an int value of one of the operands, forcing the other value to unbox as well. It is also unarguably most similar to the regular i1 == i2 comparison used for primitive int values.

Как сравнить два числа в java

Аватар пользователя Сергей Якимович

Cравнить два числа можно с помощью метода compare() :

Рекомендуемые курсы

Похожие вопросы

  • java строки
  • Java сравнение
  • Java сравнение
  • Java массивы
  • Java сравнение
  • Java массивы
  • О нас
  • Карьера в Хекслете
  • Магазин мерча
  • Условия использования
  • Соглашение об обработке ПД
  • Публичная оферта
  • Акции
  • 8 800 100 22 47 бесплатно по РФ
  • +7 495 085 28 38 бесплатно по Москве

ООО «Хекслет Рус» 432071, г. Ульяновск, пр-т Нариманова, дом 1Г, оф. 23 ОГРН 1217300010476

Как сравнить два вещественных числа без if?

Собственно, надо сравнить два числа, не используя условных операторов и операций сравнения. Язык — Java.
Для целых чисел проблем никаких нет, все делается в одну строку. Проблемы начинаются, если числа вещественные. Вообще, мой алгоритм такой: отнять одно число от другого и посмотреть на знак получившегося выражения. Но это не сработает для double, так как знак можно получить операциями сдвига, которые определены только для целых чисел. привести к целому тоже нельзя, потому что если разница чисел меньше единицы, то алгоритм отработает не верно. Придумал такой трюк:

Похожие статьи