Хорошо ли использовать порядковый номер перечисления?
У меня есть перечисление:
public enum Persons {
CHILD,
PARENT,
GRANDPARENT;
}
Есть ли проблема с использованием метода ordinal()
для проверки "иерархии" между членами enum? Я имею в виду - есть ли недостатки при его использовании, исключая многословие, когда кто-то может случайно изменить порядок в будущем.
Или лучше сделать что-то подобное:
public enum Persons {
CHILD(0),
PARENT(1),
GRANDPARENT(2);
private Integer hierarchy;
private Persons(final Integer hierarchy) {
this.hierarchy = hierarchy;
}
public Integer getHierarchy() {
return hierarchy;
}
}
Ответы
Ответ 1
Если вы ссылаетесь на метод javadoc для ordinal
в Enum.java
:
Большинство программистов не будут использовать этот метод. это предназначенные для использования сложными структурами данных на основе enum, такими как как java.util.EnumSet
и java.util.EnumMap
.
Во-первых - прочитайте руководство (javadoc в этом случае).
Во-вторых - не пишите хрупкий код. Значения перечисления могут измениться в будущем, а ваш второй пример кода намного более понятен и поддерживается.
Вы определенно не хотите создавать проблемы для будущего, если новое значение enum (скажем) вставлено между PARENT
и GRANDPARENT
.
Ответ 2
Первый способ не является понятным для понимания, поскольку вам нужно прочитать код, в котором перечисления используются для понимания того, что порядок перечисления имеет значение.
Он очень подвержен ошибкам.
public enum Persons {
CHILD,
PARENT,
GRANDPARENT;
}
Второй способ лучше, чем сам по себе:
CHILD(0),
PARENT(1),
GRANDPARENT(2);
private SourceType(final Integer hierarchy) {
this.hierarchy = hierarchy;
}
Конечно, порядки значений перечисления должны соответствовать иерархическому порядку, предоставляемому аргументами конструктора enum.
Он представляет некоторую избыточность, так как и значения перечисления, и аргументы конструктора перечисления передают их иерархию.
Но почему это проблема?
Перечисления предназначены для представления постоянных и не часто меняющихся значений.
Использование перечисления OP хорошо иллюстрирует хорошее использование перечислений:
CHILD, PARENT, GRANDPARENT
Перечисления не предназначены для представления значений, которые часто перемещаются.
В этом случае использование перечислений, вероятно, не самый лучший выбор, так как он часто нарушает клиентский код, который его использует, и, кроме того, он заставляет перекомпилировать, повторно упаковывать и повторно развертывать приложение при каждом изменении значения перечисления.
Ответ 3
Использование ordinal()
не рекомендуется, так как изменения в объявлении перечисления могут влиять на порядковые значения.
UPDATE:
Стоит отметить, что поля перечисления являются константами и могут иметь дублированные значения, т.е.
enum Family {
OFFSPRING(0),
PARENT(1),
GRANDPARENT(2),
SIBLING(3),
COUSING(4),
UNCLE(4),
AUNT(4);
private final int hierarchy;
private Family(int hierarchy) {
this.hierarchy = hierarchy;
}
public int getHierarchy() {
return hierarchy;
}
}
В зависимости от того, что вы планируете делать с hierarchy
, это может быть вредным или полезным.
Кроме того, вы можете использовать константы enum для создания собственного EnumFlags
вместо использования EnumSet
, например
Ответ 4
Если вы хотите создавать отношения между значениями enum, вы можете использовать трюк использования других значений enum:
public enum Person {
GRANDPARENT(null),
PARENT(GRANDPARENT),
CHILD(PARENT);
private final Person parent;
private Person(Person parent) {
this.parent = parent;
}
public final Parent getParent() {
return parent;
}
}
Обратите внимание, что вы можете использовать только значения перечисления, которые были объявлены лексически до того, который вы пытаетесь объявить, поэтому это работает только в том случае, если ваши отношения образуют ациклический ориентированный граф (а порядок, который вы объявляете, является допустимым топологическим типом).
Ответ 5
Как было предложено Джошуа Блохом в "Эффективной Java", нецелесообразно выводить значение, связанное с перечислением из его порядкового номера, поскольку изменения порядка упорядочения значений перечисления могут нарушить закодированную вами логику.
Второй упомянутый вами подход следует именно тому, что предлагает автор, который хранит значение в отдельном поле.
Я бы сказал, что альтернатива, которую вы предложили, определенно лучше, потому что она более расширяема и удобна в обслуживании, поскольку вы развязываете порядок значений перечисления и понятие иерархии.
Ответ 6
Я бы использовал ваш второй вариант (используя явное целое число), поэтому числовые значения назначаются вами, а не Java.
Ответ 7
Во-первых, вам, вероятно, даже не нужно числовое значение порядка - это
что Comparable
для и Enum<E>
реализует Comparable<E>
.
Если по какой-то причине вам понадобится числовое значение порядка, да, вы должны
используйте ordinal()
. Это для чего.
Стандартная практика Java Enums
заключается в сортировке по порядку объявления,
поэтому Enum<E>
реализует Comparable<E>
и почему
Enum.compareTo()
final
.
Если вы добавите свой собственный нестандартный код сравнения, который не используется
Comparable
и не зависит от порядка объявления, вы просто
собирается запутать кого-либо еще, кто пытается использовать ваш код, в том числе
ваше собственное будущее. Никто не ожидает, что этот код будет существовать;
они ожидают, что Enum
будет Enum
.
Если пользовательский заказ не соответствует порядку декларации, любой
взгляд на декларацию будет запутан. Если это произойдет
(случается, в данный момент) соответствуют порядку декларации, любому
глядя на это, он будет ожидать этого, и они собираются
получить неприятный шок, когда в какой-то будущий день этого не произойдет. (Если вы пишете
кода (или тестов), чтобы убедиться, что пользовательский заказ соответствует
порядок объявления, вы просто усиливаете, как это не нужно.)
Если вы добавите свое собственное значение заказа, вы создадите головные боли обслуживания
для себя:
- вам нужно убедиться, что ваши значения
hierarchy
уникальны.
- Если вы добавите значение в середине, вам нужно перенумеровать все
последующие значения
Если вы беспокоитесь, кто-то может случайно изменить порядок в
в будущем напишите unit test, который проверяет порядок.
В сумме, в бессмертных словах Пункт 47:
знать и использовать библиотеки.
P.S. Кроме того, не используйте Integer
, если вы имеете в виду int
. 🙂
Ответ 8
Согласно java doc
Возвращает порядковый номер этой константы перечисления (ее позиция в ее enum, где исходной константе присваивается порядковый номер нуль). Большинство программистов не будут использовать этот метод. это предназначенные для использования сложными структурами данных на основе enum, такими как EnumSet и EnumMap.
Вы можете контролировать порядковый номер, изменяя порядок перечисления, но вы не можете его явно указывать. Один способ обхода - предоставить дополнительный метод в вашем перечислении для нужного числа.
enum Mobile {
Samsung(400), Nokia(250),Motorola(325);
private final int val;
private Mobile (int v) { val = v; }
public int getVal() { return val; }
}
В этой ситуации Samsung.ordinal() = 0
, но Samsung.getVal() = 400
.
Ответ 9
Это не прямой ответ на ваш вопрос. Скорее лучший подход для вашего использования. Таким образом, следующий разработчик будет явно знать, что значения, назначенные свойствам, не должны быть изменены.
Создайте класс со статическими свойствами, который будет имитировать ваш перечисление:
public class Persons {
final public static int CHILD = 0;
final public static int PARENT = 1;
final public static int GRANDPARENT = 2;
}
Затем используйте так же, как перечисление:
Persons.CHILD
Он будет работать для большинства простых случаев использования. В противном случае вы можете отсутствовать в таких параметрах, как valueOf(), EnumSet, EnumMap или values ().