Как лучше сравнивать перечисляемые типы в Java

java-enum

Недавно на Stack Overflow я наткнулся на, казалось бы, простой вопрос: «Что лучше использовать для сравнения enum’ов — == или equals()?». Вы, конечно, можете сходу ответить, что никакой разницы нет, но будете неправы — в ответах к этому вопросу было приведено много интересных аргументов в пользу обоих вариантов. Я решил, что будет интересно перевести этот спор на русский язык.

Они же оба работают, верно?

Да. Как написано в документации, «допустимо использовать оператор == вместо метода equals, если доподлинно известно, что хотя бы один из них ссылается на перечислимый тип» («it is permissible to use the == operator in place of the equals method when comparing two object references if it is known that at least one of them refers to an enum constant»). Причина этого очень простая — каждый из объектов enum’а создаётся только единожды, и поэтому, если вы создадите десять переменных равных SomeEnum.RED, они все будут ссылаться на один и тот же объект (а оператор == как раз это и проверяет).

Какие есть преимущества у оператора ==?

  • Он никогда не выбросит NullPointerException:
  • В одном из ответов приводилась цитата Джошуа Блоха (автор книги «Effective Java»; видимо, и цитата оттуда) о том, что этот оператор работает быстрее, и если гарантируется уникальность каждого экземпляра класса, то стоит использовать именно его.
  • Как известно, сравнения через == проверяются на соответствия типов во время компиляции (это хорошо, т.к. поможет вовремя выявить ошибку):
  • Этот вариант короче, и сразу понятно, что происходит именно проверка равенства (т.е. вариант более читаемый).

Ого, как серьёзно все подошли к вопросу! Ну теперь точно буду использовать оператор равенства.

Не спешите так. Не все единогласно за ==. Вот что пишут сторонники equals():

  • Нет ни единого случая, когда переменная перечисляемого типа должна быть равна null — если вы так описываете какое-то особое состояние, то его можно просто заменить на ещё одно допустимое состояние enum’а. А значит, NPE не надо скрывать, так как это, вероятнее всего, ошибка, и чем раньше о ней станет известно, тем лучше.
  • Аргумент про скорость == весьма сомнителен. Современные компиляторы, скорее всего умеют заменять equals на == самостоятельно. Если это не так (как доказали позже, это действительно не так), то это проблема Java, над которой нужно работать.
  • Какой Java-программист не знает, что делает equals? Такой вариант наоборот более читаем, так как для объектов мы привыкли использовать именно метод equals. Значит, и для enum’ов нужно поступать так же, чтобы не возникало путаницы.

Пётр Соковых, транслятор двоичного кода в русский язык