Цикл for для перебора перечисления в Java

876

У меня есть enumв Java для основных и промежуточных направлений:

public enum Direction {
   NORTH,
   NORTHEAST,
   EAST,
   SOUTHEAST,
   SOUTH,
   SOUTHWEST,
   WEST,
   NORTHWEST
}

Как я могу написать forцикл, который повторяет каждое из этих enumзначений?

Ник Мейер
источник

Ответы:

1400

.values()

Вы можете вызвать values()метод в вашем enum.

for (Direction dir : Direction.values()) {
  // do what you want
}

Этот values()метод неявно объявлен компилятором . Так что это не указано в Enumдок.

notnoop
источник
43
Почему этот метод values ​​() не указан здесь в java.lang.enum
jacktrades
80
@jacktrades: это неявный метод, который существует только в компиляторе. Поэтому базовый класс не может объявлять метод с тем же именем, и поэтому он не включается в автоматически сгенерированные Javadocs. docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2
Торбен,
4
Как ни странно, это упоминается в документе valueOf ()
greg7gkb
129

Все константы типа enum можно получить, вызвав неявный public static T[] values()метод этого типа:

 for (Direction d : Direction.values()) {
     System.out.println(d);
 }
DFA
источник
@ RAnders00 Правда. Но все же ответ действителен, и формат действительно не имеет значения (по крайней мере для меня)
dARKpRINCE
Что делает #?
YoTengoUnLCD
@YoTengoUnLCD По сути, это говорит о том, что values ​​() является частью объекта Enum. например, Enum#values()=Enum.values()
центре внимания
Хм, прости, я не слежу, это так же, как использовать .(всегда?)?
YoTengoUnLCD
3
@YoTengoUnLCD Хэштегом является синтаксис JavaDoc, а не код Java.
Джефф Г
62

Вы можете сделать это следующим образом:

for (Direction direction : EnumSet.allOf(Direction.class)) {
  // do stuff
}
toluju
источник
1
При условии, что вы импортируете java.util.EnumSet
Nate
8
Супер полезно для циклов foreach Java8. EnumSet.allOf (Enum.class) .forEach (бла -> метод (бла))
Hiro2k
1
@ Hiro2k Вы также можете сделать Arrays.stream(Enum.values()).forEach(...)- поток будет последовательным
RAnders00
1
@ Schatten хорошо, это setвместо array. Это не «лучше», хотя, на мой взгляд, лучше описывает значения перечисления, потому что из определения множества значения в множестве не могут повторяться (как в перечислении), тогда как значения в массиве могут быть.
Jezor
2
@Jezor Это лучший выбор, когда вам действительно нужен очень быстрый набор перечислений, таких как битовые флаги, хотя он кажется слишком сложным для простой итерации.
Schatten
44

Streams

До Java 8

for (Direction dir : Direction.values()) {
            System.out.println(dir);
}

Java 8

Мы также можем использовать лямбду и потоки ( Tutorial ):

Stream.of(Direction.values()).forEachOrdered(System.out::println);

Почему forEachOrderedи не forEachс потоками?

Поведение forEachявляется явно недетерминированным, когда as forEachOrderedвыполняет действие для каждого элемента этого потока в порядке обнаружения потока, если поток имеет определенный порядок встречи. Так forEachчто не гарантирует, что заказ будет сохранен.

Также при работе с потоками (особенно параллельными) имейте в виду природу потоков. Согласно документу :

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

Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...

Здесь, если операция отображения выполняется параллельно, результаты для одного и того же ввода могут отличаться от запуска к выполнению из-за различий в планировании потоков, тогда как при использовании лямбда-выражения без сохранения состояния результаты всегда будут одинаковыми.

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

Потоки могут иметь или не иметь определенный порядок встречи. Наличие у потока порядка встречи зависит от источника и промежуточных операций.

akhil_mittal
источник
Как и во всех потоковых операциях, следует помнить о состоянии отсутствия потоков и ограничениях побочных эффектов. Docs.oracle.com/javase/8/docs/api/java/util/stream/… . Эти 2 варианта итерации enum значительно отличаются в этом отношении.
buzz3791
19

Если вы не заботитесь о заказе, это должно сработать:

Set<Direction> directions = EnumSet.allOf(Direction.class);
for(Direction direction : directions) {
    // do stuff
}
Том Джефферис
источник
2
При условии, что вы импортируете java.util.EnumSet и java.util.Set
Nate
4
Из документации дляEnumSet : Итератор, возвращенный методом итератора, перебирает элементы в их естественном порядке (порядок, в котором объявлены константы перечисления) . Это гарантирует, что порядок итерации соответствует порядку, возвращенному Enum.values().
Джефф Г
18
    for (Direction  d : Direction.values()) {
       //your code here   
    }
АКФ
источник
5

Java8

Stream.of(Direction.values()).forEach(System.out::println);

с Java5 +

for ( Direction d: Direction.values()){
 System.out.println(d);
}
Рагу К Наир
источник
1
ой, извини. Я только что понял, что akhil_mittal уже выложил подобный ответ.
Рагу К Наир
Когда и почему я должен использовать Stream.of (o) .forEach? Цикл for кажется гораздо более читабельным.
Джереми
Нет, если вы знакомы с функциональным программированием.
Алексис Дафреной
5

Попробуйте использовать для каждого

for ( Direction direction : Direction.values()){
  System.out.println(direction.toString());
}
Irazza
источник
4

Больше методов в Java 8:

Использование EnumSetсforEach

EnumSet.allOf(Direction.class).forEach(...);

Использование Arrays.asListсforEach

Arrays.asList(Direction.values()).forEach(...);
Niver
источник