Я знаю, что перечисления Java скомпилированы в классы с частными конструкторами и несколькими открытыми статическими членами. При сравнении двух членов данного перечисления я всегда использовал .equals()
, например,
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
Однако я только что натолкнулся на некоторый код, который использует оператор equals ==
вместо .equals ():
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
Какой оператор мне следует использовать?
Ответы:
Оба технически правильны. Если вы посмотрите на исходный код для
.equals()
, он просто откладывает на==
.Я использую
==
, однако, поскольку это будет нуль-безопасным.источник
.equals()
его использовать? Я знаю, что нет.Может
==
быть использован наenum
?Да: перечисления имеют жесткие элементы управления экземплярами, что позволяет использовать их
==
для сравнения. Вот гарантия, предоставляемая спецификацией языка (выделено мной):Эта гарантия достаточно сильна, и Джош Блох рекомендует, что, если вы настаиваете на использовании одноэлементного шаблона, лучший способ реализовать его - это использовать одноэлементный
enum
(см. Effective Java 2nd Edition, Item 3: Enforment свойство singleton с помощью частный конструктор или тип enum, а также потокобезопасность в Singleton )Каковы различия между
==
иequals
?Напоминаем, что нужно сказать, что в общем случае
==
это НЕ жизнеспособная альтернативаequals
. Однако, когда это так (например, сenum
), есть два важных различия, которые следует учитывать:==
никогда не бросаетNullPointerException
==
подлежит проверке совместимости типов во время компиляцииСледует
==
ли использовать, когда это применимо?Блох, в частности, упоминает, что неизменные классы, которые имеют надлежащий контроль над своими экземплярами, могут гарантировать своим клиентам, что они
==
могут использоваться.enum
специально упоминается в качестве примера.Подводя итог, аргументы для использования
==
наenum
:источник
Color nothing = null;
это ИМХО ошибка и должно быть исправлено, ваше перечисление имеет два значения, а не три ( см. комментарий Тома Хоутина) 4. Во время компиляции это безопаснее : хорошо, ноequals
все равно вернетсяfalse
. В конце я не покупаю это, я предпочитаюequals()
для удобочитаемости (см. Комментарий Кевина).foo.equals(bar)
более читабельным, чемfoo == bar
Использование
==
для сравнения двух значений перечисления работает, потому что для каждой константы перечисления существует только один объект.Напомним, что на самом деле нет необходимости использовать
==
для написания нулевого кода, если вы пишетеequals()
так:Это лучшая практика, известная как сравнение констант слева, которой вы обязательно должны следовать.
источник
.equals()
вводе строковых значений, но я все еще думаю, что это дурацкий способ написания нулевого кода. Я бы предпочел иметь оператор (или метод, но я знаю, что [нулевой объект] .equals никогда не будет нулевым в Java из-за того, как работает оператор точки), который всегда будет нулевым, независимо от порядок, в котором он используется. Семантически оператор «равно» должен всегда коммутировать.?.
), я буду продолжать использовать эту практику при сравнении с константами, и, TBH, я не нахожу это дурацким, может быть, просто менее "естественным".null
Перечисление , как правило , ошибка. У вас есть это перечисление всех возможных значений, а вот еще одно!@Nullable
, я считаю Сравнить константы слева антипаттерном, потому что он распространяет неоднозначность относительно того, какие значения могут быть или не быть нулевыми. Типы enum почти никогда не должны быть@Nullable
, поэтому нулевое значение будет ошибкой программирования; в таком случае, чем раньше вы бросите NPE, тем больше вероятность того, что вы обнаружите ошибку в программировании, если допустите, что она будет нулевой. Таким образом, «лучшая практика ... которой вы обязательно должны следовать» совершенно неверна, когда дело доходит до типов enum.Как уже говорили другие, оба
==
и.equals()
работают в большинстве случаев. Уверенность во время компиляции в том, что вы не сравниваете совершенно разные типы объектов, на которые указывали другие, является допустимой и полезной, однако конкретный вид ошибки сравнения объектов двух разных типов времени компиляции также будет найден FindBugs (и, вероятно, Eclipse / IntelliJ проверяет время компиляции), поэтому компилятор Java, обнаружив его, не добавляет такой дополнительной безопасности.Однако:
==
никогда не бросает NPE на мой взгляд , является недостатком в==
. Вряд ли когда-либо возникнет необходимость вenum
типахnull
, поскольку любое дополнительное состояние, которое вы можете выразить через,null
может быть просто добавленоenum
в качестве дополнительного экземпляра. Если это неожиданноnull
, я предпочел бы иметь NPE, чем==
молча оценивать как ложное. Поэтому я не согласен с более безопасным во время выполнения мнением; лучше привыкнуть никогда не оставлятьenum
ценности@Nullable
.==
это быстрее , также поддельный. В большинстве случаев вы будете звонить.equals()
по переменной, компиляции времени тип является классом перечисления, а также в тех случаях , компилятор может знать , что это то же самое,==
(потому чтоenum
«Sequals()
метод не может быть переопределен) и может оптимизировать вызов функции прочь. Я не уверен, что компилятор в настоящее время делает это, но если это не так, и это в целом вызывает проблемы с производительностью Java, то я бы скорее исправил компилятор, чем 100 000 Java-программистов изменили свой стиль программирования в соответствии с требованиями характеристики производительности конкретной версии компилятора.enums
являются объектами. Для всех других типов объектов стандартное сравнение -.equals()
нет==
. Я думаю, что делать исключение опасно,enums
потому что вы можете случайно сравнить объекты с объектами==
вместоequals()
, особенно если выenum
преобразуете класс в не перечислимый. В случае такого рефакторинга, пункт « Работает» сверху неверен. Чтобы убедить себя в том, что использование==
является правильным, вам нужно проверить, является ли рассматриваемое значениеenum
или примитивом; если бы это был неenum
класс, это было бы неправильно, но легко пропустить, потому что код все еще компилируется. Единственный случай, когда использование.equals()
было бы неправильно, если бы эти значения были примитивами; в этом случае код не будет компилироваться, поэтому его будет гораздо сложнее пропустить. Следовательно,.equals()
гораздо легче определить, как правильно, и безопаснее от будущих рефакторингов.Я действительно думаю, что язык Java должен был определить == для объектов, чтобы вызвать .equals () для значения слева, и ввести отдельный оператор для идентификации объекта, но это не то, как Java была определена.
Таким образом, я все еще думаю, что аргументы в пользу использования
.equals()
дляenum
типов.источник
enum
в качествеswitch
цели, поэтому они немного особенные.String
Это тоже немного особенное.Я предпочитаю использовать
==
вместоequals
:Другая причина, в дополнение к другим, уже обсужденным здесь, состоит в том, что вы можете внести ошибку, не осознавая этого. Предположим, у вас есть эти перечисления, которые точно такие же, но в разделенных пакетах (это не часто, но это может произойти):
Первое перечисление :
Второе перечисление:
Затем предположим, что вы используете равенства, как в следующем
item.category
,first.pckg.Category
но вы импортируете второй enum (second.pckg.Category
) вместо первого, не осознавая этого:Таким образом, вы всегда получите
false
из-за другого перечисления, хотя вы ожидаете, потому чтоitem.getCategory()
это правдаJAZZ
. И это может быть немного трудно увидеть.Итак, если вы вместо этого используете оператор, у
==
вас будет ошибка компиляции:источник
Вот грубый временной тест для сравнения двух:
Закомментируйте IFs по одному. Вот два сравнения сверху в разобранном байт-коде:
Первый (равно) выполняет виртуальный вызов и проверяет возвращаемое логическое значение из стека. Второй (==) сравнивает адреса объектов непосредственно из стека. В первом случае больше активности.
Я провел этот тест несколько раз с обоими IF, по одному. «==» немного быстрее.
источник
В случае enum оба являются правильными и правильными !!
источник
ТЛ; др
Другим вариантом является
Objects.equals
служебный метод.Objects.equals
для нулевой безопасностиТретий вариант - статический
equals
метод, найденный вObjects
служебном классе, добавленном в Java 7 и более поздние .пример
Вот пример использования
Month
enum.Льготы
Я нахожу пару преимуществ для этого метода:
true
false
NullPointerException
Как это работает
Какая логика используется
Objects.equals
?Смотрите сами, из исходного кода Java 10 из OpenJDK :
источник
Использование чего-либо, кроме как
==
для сравнения констант перечисления, - нонсенс. Это как сравниватьclass
объектыequals
- не делай этого!Однако в Sun JDK 6u10 и более ранних версиях имелась неприятная ошибка (BugId 6277781 ), которая может быть интересной по историческим причинам. Эта ошибка не позволяла правильно использовать
==
десериализованные перечисления, хотя это, возможно, в некотором роде случайный случай.источник
Перечисления - это классы, которые возвращают один экземпляр (например, одиночные) для каждой константы перечисления, объявленной
public static final field
(неизменяемой), так что==
оператор может использоваться для проверки их равенства вместо использованияequals()
метода.источник
Перечисления легко работают с ==, потому что каждый определенный экземпляр также является одиночным. Поэтому сравнение тождеств с использованием == всегда будет работать.
Но использование ==, потому что оно работает с перечислениями, означает, что весь ваш код тесно связан с использованием этого перечисления.
Например: Enums может реализовать интерфейс. Предположим, вы используете enum, который реализует интерфейс Interface1. Если позже кто-то изменит его или представит новый класс Impl1 как реализацию того же интерфейса. Затем, если вы начнете использовать экземпляры Impl1, у вас будет много кода для изменения и тестирования из-за предыдущего использования ==.
Следовательно, лучше всего следовать тому, что считается хорошей практикой, если нет какой-либо оправданной выгоды.
источник
Одно из правил эхолота
Enum values should be compared with "=="
. Причины следующие:Наконец, что не менее
==
важно, перечисления могут быть более читабельными (менее подробными), чемequals()
.источник
Одним словом, у обоих есть плюсы и минусы.
С одной стороны, он имеет преимущества в использовании
==
, как описано в других ответах.С другой стороны, если вы по какой-либо причине замените перечисления другим подходом (обычные экземпляры классов), воспользовавшись
==
укусами. (BTDT.)источник
Хочу дополнить ответом полигеномасла:
Я лично предпочитаю равно (). Но это проверка совместимости типов. Что я считаю важным ограничением.
Для проверки совместимости типов во время компиляции объявите и используйте пользовательскую функцию в вашем перечислении.
Благодаря этому вы получаете все преимущества обоих решений: защиту NPE, легкий для чтения код и проверку совместимости типов во время компиляции.
Я также рекомендую добавить значение UNDEFINED для enum.
источник
==
? С ним==
вы получаете защиту NPE, простой для чтения код и проверку совместимости типов времени компиляции, и вы получаете все это без написания каких-либо пользовательских методов, похожих на подобные.UNDEFINED
Значение, вероятно , хорошая идея. Конечно, в Java 8 вы бы использовалиOptional
вместо этого.