【问题标题】:A 'for' loop to iterate over an enum in Java在 Java 中迭代枚举的“for”循环
【发布时间】:2010-11-09 10:49:40
【问题描述】:

我在 Java 中有一个 enum 用于基本和中间方向:

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

如何编写一个循环遍历每个enum 值的for 循环?

【问题讨论】:

标签: java loops for-loop enums


【解决方案1】:

一个枚举类型的所有常量都可以通过调用该类型的隐式public static T[] values()方法获得:

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

【讨论】:

  • @RAnders00 是的。但答案仍然有效,格式真的不重要(至少对我来说)
  • # 有什么作用?
  • @YoTengoUnLCD 基本上是说 values() 是 Enum 对象的一部分。例如Enum#values() = Enum.values()
  • 嗯,对不起,我没跟,和用.一样吗(总是?)?
  • @YoTengoUnLCD 主题标签是 JavaDoc 语法,而不是 Java 代码。
【解决方案2】:

.values()

您可以在枚举上调用values() 方法。

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

这个values() 方法是implicitly declared by the compiler。所以它没有在Enum doc 上列出。

【讨论】:

【解决方案3】:

你可以这样做:

for (Direction direction : EnumSet.allOf(Direction.class)) {
  // do stuff
}

【讨论】:

  • 如果你导入 java.util.EnumSet
  • 对 Java8 foreach 循环非常有用。 EnumSet.allOf(Enum.class).forEach(blah -> method(blah))
  • @Hiro2k 你也可以Arrays.stream(Enum.values()).forEach(...) - 流将是连续的
  • @schatten 好吧,它是 set 而不是 array。它不是“更好”,尽管我认为它更好地描述了枚举值,因为从集合的定义来看,集合中的值不能重复(如枚举),而数组中的值可以。
  • @Jezor 当您实际上需要一组非常快速的枚举(例如位标志)时,这是一个更好的选择,尽管对于简单的迭代来说似乎太复杂了。
【解决方案4】:

如果您不关心顺序,这应该可以:

Set<Direction> directions = EnumSet.allOf(Direction.class);
for(Direction direction : directions) {
    // do stuff
}

【讨论】:

  • 如果你导入 java.util.EnumSet 和 java.util.Set
  • 来自documentation for EnumSet迭代器方法返回的迭代器按照元素的自然顺序(枚举常量声明的顺序)遍历元素。这保证了迭代的顺序与Enum.values()返回的顺序相匹配。
【解决方案5】:

Java 8 之前

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

Java 8

我们还可以使用 lambda 和流 (Tutorial):

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

为什么 forEachOrdered 而不是 forEach 带有流?

forEach 的行为是明确的不确定性,因为forEachOrdered 对该流的每个元素执行一个操作,如果流具有定义的遇到顺序,则按照流的遇到顺序。所以forEach 不保证订单会被保留。

此外,在使用流(尤其是并行流)时,请记住流的性质。根据doc

如果流操作的行为参数是有状态的,则流管道结果可能是不确定的或不正确的。有状态 lambda 的结果取决于在流管道执行期间可能发生变化的任何状态。

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

在这里,如果映射操作是并行执行的,由于线程调度的差异,相同输入的结果可能会因运行不同而不同,而对于无状态 lambda 表达式,结果将始终相同。

通常不鼓励对流操作的行为参数产生副作用,因为它们通常会导致无意中违反无状态要求以及其他线程安全隐患。

流可能有也可能没有定义的相遇顺序。流是否有遇到顺序取决于源和中间操作。

【讨论】:

【解决方案6】:

Java8

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

来自 Java5+

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

【讨论】:

  • 抱歉。我刚刚意识到 akhil_mittal 已经发布了类似的答案。
  • 何时以及为什么应该使用 Stream.of(o).forEach? for 循环似乎更具可读性。
  • 如果您熟悉函数式编程,则不会。
【解决方案7】:

java 8 中的更多方法:

使用EnumSetforEach

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

使用 Arrays.asListforEach

Arrays.asList(Direction.values()).forEach(...);

【讨论】:

    【解决方案8】:

    我们可以像这样使用过滤器(JAVA 8)。

    Stream.of(Direction.values()).filter(name -> !name.toString().startsWith("S")).forEach(System.out::println);
    

    【讨论】:

      猜你喜欢
      • 2014-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-09
      • 2019-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多