Вы должны определить нулевое / неизвестное значение для перечислений Java? - PullRequest
36 голосов
/ 22 августа 2011

Когда вы определяете enum для чего-то, что может быть «неопределенным» в ваших интерфейсах, вы должны

  • определить для этого отдельное значение enum или
  • просто использовать enumValue = null для этих ситуаций?

Например,

serviceX.setPrice (Price priceEnum)

enum Price {
 CHEAP, EXPENSIVE, VERRRY_EXPENSIVE, UNKNOWN
}

и priceEnum.UNKNOWN при необходимости

или

enum Price {
 CHEAP, EXPENSIVE, VERRRY_EXPENSIVE
}

и priceEnum = null, когда это необходимо?

Имея небольшую дискуссию по этому вопросу. Несколько моментов, которые приходят на ум:

  • использование Price.UNKNOWN сохраняет некоторый код "if (price == null)". Вы можете обрабатывать все значения Price x в одном корпусе переключателя
  • В зависимости от технологии просмотра может быть проще локализовать Price.UNKNOWN
  • использование Price.UNKNOWN вызывает проблемы с «магическим числом» в коде, IMO. Здесь у нас есть Price.UNKNOWN, в другом месте может быть Color.UNDEFINED, Height.NULLVALUE и т. Д.
  • использование priceValue = null более единообразно с тем, как обрабатываются другие типы данных в Java. У нас есть целое число i = null, DomainObject x = null, String s = null для неизвестных значений, не так ли?
  • Price.UNKNOWN заставляет вас решать, разрешено ли нулевое значение универсально для всех случаев использования. У нас может быть метод Price getPrice (), который может возвращать Price.UNKNOWN и setPrice (Price p), который не может принимать Price.UNKNOWN. Поскольку Price.UNKNOWN всегда включен в значения enum, эти интерфейсы выглядят немного нечистыми. Я знаю, что priceValue = null имеет ту же проблему (вы не можете определить в интерфейсе, принят ли null или нет), но он выглядит немного чище и немного менее обманчив (())

Ответы [ 5 ]

28 голосов
/ 22 августа 2011

На самом деле это пример применения шаблона нулевого объекта .ИМХО, всегда лучше иметь фиктивный объект, чем ноль.Например, вы можете добавить фиктивные методы к нулевому объекту, вместо того, чтобы разбрасывать код с помощью нулевых проверок повсюду.Очень удобно.

Также имя enum дает вам дополнительную семантику: цена неизвестна , не определена , а не заслуживает доверия , еще не известно ?И что это значит, если цена составляет ноль ?

ОБНОВЛЕНИЕ: Как указывает Аарон Дигулла , для шаблона нулевого объекта требуется память.Но на самом деле это не так в большинстве случаев.В традиционной реализации обычно используется единственный объект для объекта Null, так как нет необходимости в отдельных экземплярах.С перечислениями это становится еще лучше, потому что вы получаете одноэлементную семантику бесплатно.

Другой момент заключается в том, что ссылка null и ссылка на некоторый объект занимают одинаковый объем памяти (скажем, 4 байта на 32-разрядной машине).Это объект, на который ссылаются, который занимает некоторую дополнительную память.Но если это одноэлементная память, то здесь практически нет перегрузок памяти.

13 голосов
/ 22 августа 2011

Я бы сказал пойти с Price.UNKNOWN, если это допустимое значение для цены.

Я согласен с недостатками работы с нулевыми ссылками, которые вы упомянули, и я думаю, что они достаточно мотивируют решение.

Новые языки, например, Scala (и некоторые более старые, Haskell) полностью отделены от нулевых ссылок и вместо этого используют option / возможно монады ... по уважительным причинам.

1 голос
/ 25 марта 2014

Существует Enum-Switch-Null-Trap .Таким образом, похоже, что, как и в случае любого свойства объекта, если его не существует, оно равно null.

1 голос
/ 22 августа 2011

Зависит от того, как вы собираетесь использовать это перечисление. Если вы используете его в выражениях switch / case, это не имеет значения. Если вы создаете метод (ы) в перечислении, вы на самом деле должны определить UNKNOWN.

Например, вы можете определить абстрактный метод public abstract Icon icon();

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

0 голосов
/ 14 февраля 2015

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

Таким образом, цена может быть НЕИЗВЕСТНА (вместо нуля), цвет - нет (ноль может означать ошибку).

...