在Java中,使用for循环遍历枚举类型

940

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

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

我该如何编写一个for循环来遍历这些enum值?


Java 8: https://dev59.com/b3NA5IYBdhLWcg3wEZeT#30962181 - akhil_mittal
9个回答

1485

.values()

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

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

这个values()方法是编译器隐式声明的。因此它不会列在Enum文档中。


46
为什么这个方法 values() 没有出现在 这里 的 java.lang.enum 中? - jacktrades
83
这是一种仅存在于编译器中的隐式方法。因此,基类无法声明具有相同名称的方法,因此它不会被包括在自动生成的Javadocs文档中。详见http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2 - Torben
4
奇怪的是,在valueOf()文档中提到了这一点。 - greg7gkb

141

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

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

@RAnders00 没错。但是答案仍然有效,格式并不重要(至少对我来说)。 - dARKpRINCE
# 是什么作用? - YoTengoUnLCD
@YoTengoUnLCD,基本上它是在说values()是Enum对象的一部分。例如Enum#values() = Enum.values() - Spotlight
嗯,抱歉,我不明白,这是和使用 .(总是?)一样吗? - YoTengoUnLCD
4
这个标签使用的是JavaDoc语法,而不是Java代码。 - Jeff G

64
你可以按照以下方式实现:
for (Direction direction : EnumSet.allOf(Direction.class)) {
  // do stuff
}

2
只要您导入java.util.EnumSet。 - Nate
9
对于Java8的foreach循环非常有用。EnumSet.allOf(Enum.class).forEach(blah -> method(blah)) - Hiro2k
1
@Hiro2k 你也可以使用 Arrays.stream(Enum.values()).forEach(...) - 这个流将是顺序的。 - randers
你能解释一下为什么它比 Enum.values() 更好吗? - schatten
1
@schatten 嗯,它是一个set而不是array。它并不是“更好”,尽管在我看来它更好地描述了枚举值,因为从集合的定义来看,集合中的值不能重复(就像枚举一样),而数组中的值可以重复。 - Jezor
2
@Jezor 当你需要一个非常快速的枚举集合,比如位标志时,它是更好的选择,但对于简单的迭代来说似乎过于复杂了。 - schatten

47

Java 8之前

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

Java 8

我们还可以利用lambda表达式和流(教程):

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

为什么使用流时要使用forEachOrdered而不是forEach

forEach的行为是明确非确定性的,而forEachOrdered会为流中的每个元素执行一个操作,如果流具有定义的遇见顺序,则按照该顺序进行。因此,forEach不能保证顺序被保留。

此外,当使用流(特别是并行流)时,请牢记流的本质。根据文档

如果流操作的行为参数是有状态的,则流管道结果可能是不确定或不正确的。有状态的lambda是其结果依赖于在执行流管道期间可能更改的任何状态的lambda。

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

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

通常不建议在流操作的行为参数中引入副作用,因为它们经常会导致无意识地违反无状态要求以及其他线程安全隐患。

流可以有或没有定义的遍历顺序。是否有遍历顺序取决于源和中间操作。


2
与所有流操作一样,要注意线程状态不可变性和副作用限制。https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Statelessness。在这方面,这两个枚举迭代选项明显不同。 - buzz3791

21

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

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

2
只要您导入java.util.EnumSet和java.util.Set。 - Nate
4
根据 EnumSet 文档所述:iterator 方法返回的迭代器以枚举类型常量被声明的 自然顺序 遍历元素。这保证了迭代的顺序与 Enum.values() 返回的顺序相匹配。 - Jeff G

7

Java8

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

从Java5+开始

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

1
哦,抱歉。我刚意识到akhil_mittal已经发布了类似的答案。 - Raghu K Nair
何时以及为什么应该使用Stream.of(o).forEach?for循环似乎更易读。 - Jeremy
只有你熟悉函数式编程才不会。 - Alexis Dufrenoy

5

Java 8中的更多方法:

forEach中使用EnumSet

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

如何在使用Arrays.asListforEach的时候进行操作

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

2

场景:假设我们有一定数量的卡片类型。每种卡片类型都有相关费用和加入奖励。

package enumPkg;

public enum CardTypes {
//Each enum is object
DEBIT(10,20),
CREDIT(0,10),
CRYPTO(5,30);

//Object properties
int fees;
int bonus;

//Initilize object using constructor
CardTypes(int fee, int bonus){
    this.fees = fee;
    this.bonus = bonus;
}

//access object property
public int getFees(){
    return this.fees;
}

public int getBonus(){
    return this.bonus;
}

}

现在要在其他类中访问枚举。按照以下步骤进行Java操作:

package enumPkg;

public class EnumClass {
public static void main(String[] args) {
    CardTypes cardType = CardTypes.CREDIT; //Each enum element is public static final, when accessed returns a object
    System.out.println(cardType);

    System.out.println("Debit card fees : "+CardTypes.DEBIT.getFees());
    System.out.println("Debit card bonus : "+CardTypes.DEBIT.getBonus());

    CardTypes[] cardTypes = CardTypes.values();//return array of CardTypes i.e all enum elements we have defined

    for (CardTypes type : CardTypes.values()) {
        System.out.println(type); //particular enum object
        System.out.println(type.ordinal()); //return enum position
        System.out.println("Bonus : "+type.getBonus()); //return enum object property: Bonus
        System.out.println("Fees  : "+type.getFees());//return enum object property: Fees
    }

}
}

输出:

CREDIT
Debit card fees : 10
Debit card bonus : 20
DEBIT
0
Bonus : 20
Fees  : 10
CREDIT
1
Bonus : 10
Fees  : 0
CRYPTO
2
Bonus : 30
Fees  : 5

2
我们可以使用这样一个过滤器(JAVA 8)。
Stream.of(Direction.values()).filter(name -> !name.toString().startsWith("S")).forEach(System.out::println);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接