Подтвердить что ты не робот

Перечисления Java и статические константы

Я просматриваю код Java, который поддерживается другими частями компании, кстати, некоторые бывшие разработчики C и С++. Одна вездесущая вещь - использование статических целочисленных констант, таких как

class Engine {
    private static int ENGINE_IDLE = 0;
    private static int ENGINE_COLLECTING = 1;
    ...
}

Помимо недостающего "финального" квалификатора, я немного обеспокоен таким кодом. То, что я хотел бы видеть, будучи обученным в основном на Java из школы, будет чем-то более похож на

class Engine {
    private enum State { Idle, Collecting };
    ...
}

Однако аргументы терпят неудачу. Почему, если вообще, последнее лучше, чем первое?

4b9b3361

Ответ 1

Почему, если вообще, последнее лучше чем первый?

Это намного лучше, потому что это дает вам безопасность типов и самодокументируется. При использовании целочисленных констант вы должны посмотреть документ API, чтобы узнать, какие значения действительны, и ничто не мешает вам использовать недопустимые значения (или, возможно, хуже целые константы, которые полностью не связаны). С помощью Enums подпись метода сообщает вам, какие значения действительны (автозаполнение IDE будет работать), и невозможно использовать недопустимое значение.

Шаблон "целочисленные константы", к сожалению, очень распространен даже в стандартном API Java (и широко копируется оттуда), потому что у Java не было Enums до Java 5.

Ответ 2

Отрывок из официальных документов http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html:

В этом шаблоне много проблем, например:

  • Не typeafe. Поскольку сезон - это просто int, вы можете передать любую другую стоимость int, где требуется сезон, или добавить два сезона вместе (что не имеет смысла).
  • Нет пространства имен. Вы должны префиксные константы int enum со строкой (в данном случае SEASON_), чтобы избежать столкновений с другими типами enumum.
  • Brittleness - поскольку int enums являются константами времени компиляции, они скомпилируются в используемые им клиенты. Если новая константа добавляется между двумя существующими константами или порядок изменяется, клиенты должны быть перекомпилированы. Если это не так, они все равно будут работать, но их поведение будет undefined.
  • Отпечатанные значения неинформативны - потому что они просто ints, если вы печатаете одно из всего, что вы получаете, это число, которое ничего не сообщает о том, что он представляет, или даже о том, какой тип он есть.

И это просто охватывает его. Аргумент с одним словом будет состоять в том, что перечисления являются более читабельными и информативными.

Еще одна вещь - перечисления, как классы. могут иметь поля и методы. Это дает вам возможность включать дополнительную информацию о каждом типе состояния в самом перечислении.

Ответ 3

Потому что перечисления обеспечивают безопасность типов. В первом случае вы можете передать любое целое число, и если вы используете перечисление, вы ограничены Idle и Collecting.

FYI: http://www.javapractices.com/topic/TopicAction.do?Id=1.

Ответ 4

Используя int для ссылки на константу, вы не заставляете кого-то фактически использовать эту константу. Так, например, у вас может быть метод, который принимает состояние ядра, к которому кто-то может с радостью вызвать:

engine.updateState(1);

Использование enum заставляет пользователя придерживаться пояснительной метки, поэтому она более разборчива.

Ответ 5

Существует одна ситуация, когда статическая константа предпочтительнее (скорее, что код является устаревшим с тонной зависимостью), и это когда член этого значения не будет/может позже не быть конечным.

Представьте, если позже вы можете добавить новое состояние, например Collected. Единственный способ сделать это с перечислением - отредактировать исходный код, который может быть проблемой, если модификация выполняется, когда уже много кода обрабатывает его. Кроме этого, я лично не вижу причин, почему перечисление не используется.

Просто моя мысль.

Ответ 6

  • Readabiliy. Когда вы используете перечисления и делаете State.Idle, читатель сразу же узнает, что вы говорите о состоянии бездействия. Сравните это с 4 или 5.

  • Тип безопасности. При использовании перечисления, даже по ошибке, пользователь не может передать неправильное значение, поскольку компилятор заставит его использовать один из предварительно объявленных значений в перечислении. В случае простых целых чисел он мог бы даже пройти -3274.

  • Поддержание работоспособности. Если вы хотите добавить новое состояние Waiting, было бы очень легко добавить новое состояние, добавив постоянное ожидание в ваше состояние перечисления без какого-либо путаницы.

Ответ 7

Причины из спецификации, которую цитирует Лайцик, более подробно объясняются в Josh Bloch Effective Java, Item 30. Если у вас есть доступ к этой книге, я бы рекомендовал ее изучить. Java Enums - это полноценные классы, поэтому вы получаете безопасность типа компиляции. Вы также можете дать им поведение, обеспечивающее лучшую инкапсуляцию.

Ответ 8

Первый используется в коде, который начинался с pre-1.5. На самом деле, другой общей идиомой было определение ваших констант в интерфейсе, потому что у них не было никакого кода.

Ответ 9

Перечисления также дают вам большую гибкость. Поскольку Enums являются, по существу, классами, вы можете увеличить их с помощью полезных методов (например, предоставить интернационализированную строку ресурсов, соответствующую определенному значению в перечислении, конвертировать назад и вперед между экземплярами типа перечисления и другими представлениями, которые могут потребоваться, и т.д. )