enum.values ​​() - детерминированный порядок возвращаемых перечислений

105

У меня есть перечисление SOME_ENUM:

public enum SOME_ENUM {
  EN_ONE,
  EN_TWO,
  EN_THREE;
}

Будем SOME_ENUM.values()всегда возвращать перечисления в порядке деклараций перечислений: EN_ONE, EN_TWO, EN_THREE? Это правило или не гарантируется, что в следующих выпусках JDK его не изменят?

Скараб
источник
1
Я перебираю свое перечисление, чтобы заполнить список, который, чем в другом месте кода, который я читал, повторял это перечисление.
Skarab
11
@MitchWheat По той же причине, по которой вы полагались бы на порядок сохранения списка: потому что JDK - это инструмент, который дает вам определенные гарантии, и полагаясь на эти гарантии, вы можете писать более сжатый и лучший код. Правда, вопрос "А что, не изменится?" невозможно ответить, на это, конечно, нельзя полагаться, нет такой гарантии.
Fletch

Ответы:

144

В спецификации языка Java используется этот явный язык:

@return массив, содержащий константы этого типа перечисления, в порядке их объявления [Источник]

Так что да, они будут возвращены в порядке декларации. Стоит отметить, что порядок может измениться со временем, если кто-то изменит класс, поэтому будьте очень осторожны с тем, как вы это используете.

GaryF
источник
1
Если кто-то добавит значение посередине в более поздней версии кода, это может вас накачать, так как это изменит порядковое значение других элементов (см. Метод Enum.ordinal ()). По этой причине лучше не полагаться на порядковый номер как на механизм сериализации (т.е. не хранить его в базе данных).
Мэтт
1
Ссылка на источник этой спецификации?
Дэн Гран
Документ Java 8
Дрю Стивенс
16

Да, мы гарантированно вернем их в таком порядке.

Однако вам не следует полагаться на это и на ordinal()значение, поскольку оно может измениться, например, после вставки новых элементов.

Божо
источник
+1 за мудрый совет. Что касается ordinal (), в Effective Java предлагается добавить поле члена в тип перечисления.
ide
9

Это определяется порядком, в котором объявлены ваши значения. Однако нет никакой гарантии, что вы (или кто-то другой) не измените порядок / вставите / удалите значения в будущем . Так что не стоит полагаться на порядок.

Эффективная Java 2nd. Редакция посвящает свой пункт 31 тесно связанной теме: используйте поля экземпляра вместо порядковых номеров :

Никогда не извлекайте значение, связанное с перечислением, из его порядкового номера; вместо этого сохраните его в поле экземпляра.

Петер Торок
источник
3
«нет гарантии, что кто-то не изменит порядок значений в будущем» - но именно поэтому я хочу полагаться на порядок :-)! Я хочу иметь возможность переупорядочивать элементы в будущем и тем самым изменить поведение моей программы. Блох прав в том, что не полагается на порядковый номер, и если в примере задающего вопрос действительно используются перечисления вроде EN_TWO, то он полагается на порядковый номер и не должен этого делать. Но полагаться на порядок - это нормально. Фактически, поскольку порядок гарантирован, создание поля специально для порядка означало бы написание избыточного кода, чего не следует делать в таких книгах, как «Эффективная Java».
Fletch
@ Флетч, извини, я не совсем понимаю тебя. Для меня это звучит так, будто вы пытаетесь использовать его enumдля какой-то цели, для которой он не предназначен.
Péter Török
допустим, у вас есть знаменитое перечисление «Планета». В пользовательском интерфейсе вы хотите перечислить планеты в порядке их удаления от Солнца. Как вам лучше всего этого добиться? Я бы упорядочил константы планет в правильном порядке внутри класса перечисления, а затем просто перечислил бы перечисление в пользовательском интерфейсе. Поскольку порядок надежен, это будет работать. Я говорю именно об этом. Если в один прекрасный день Земля приблизится к Солнцу, чем Марс, конечно, в такой момент первое, что вам захочется, будет поддерживать ваш код! Итак, вы идете в свой класс «Планета» и перемещаете ЗЕМЛЮ перед МАРСОМ.
Флетч
@Fletch, Земля уже ближе к Солнцу, чем Марс ;-) но я понимаю, что вы имеете в виду. Однако в этом случае порядок планет на самом деле является функцией их среднего расстояния от Солнца, что не является простым порядковым номером, поэтому, IMHO, его лучше хранить как отдельное поле для каждой планеты. Затем вы можете использовать тривиальный компаратор для сравнения планет на основе их среднего расстояния от Солнца и упорядочить их с помощью этого компаратора. Это ИМХО чистое и надежное решение. Принимая во внимание, что ваше решение ломается, как только, например, новый коллега решает, что планеты, очевидно, должны быть перечислены в алфавитном порядке ;-)
Петер Тёрок
1
Хахаха эммм да ну в любом случае это заговор, Марса нет. Изначально я собирался использовать Сатурн, но не мог вспомнить, с какими планетами он находится, но план Марса, похоже, дал обратный эффект :-). В любом случае ... в этом случае компаратор был бы хорош, но, очевидно, имеет обратную сторону, требующую большего количества кода. Я думаю, что если вы полагаетесь на упорядочение исходного кода, документирование этого в комментариях к классу было бы хорошо. Ваш коллега может даже прочитать это.
Флетч
7

Другие ответы хороши, но не комментируйте это:

«Это правило или нет гарантии, что оно не будет изменено в следующих выпусках Jdk?»

Я не верю, что существуют гарантии на будущие JDK, поэтому вам даже не стоит о них беспокоиться. Невозможно будет обеспечить их соблюдение, будущие лидеры JDK могут просто отказаться от таких гарантий. Это похоже на Вестминстерскую систему парламента: «Ни один парламент не может связывать будущий парламент».

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

Флетч
источник