简体   繁体   中英

In Java how do write code to loop round an arbitary enum?

How do write code to loop round an arbitary enum ?

So in the code below in use an enum as the values to provide to create a Html select loop, but I cannot see how to pass an enum to the method, or how to access the standard .values() and .ordinal() methods. so currently I have hardcoded a particular enum RenameFileOptions but I want to work with any enum, I could parse enum class eg RenameFileOptions.class but still how would I access .name() , .values() and .ordinal()

public ContainerTag addCombo(UserOption userOption, int selectedValue)
{
    return div(
                label(userOption.getLabel().getMsg())
                    .withTitle(userOption.getTooltip().getMsg()),
                select(
                    each(Arrays.asList(RenameFileOptions.values()),
                            next ->
                                iffElse(next.ordinal()==selectedValue,
                                        option(next.name()).attr(Html.SELECTED, Html.SELECTED).withValue(String.valueOf(next.ordinal())),
                                        option(next.name()).withValue(String.valueOf(next.ordinal()))
                                )
                    ))
                .withName(userOption.getOption())
            );
}

Update As there seemed to be no way to achieve this in a none hacky way I instead added a getOptions() methods to each enum, and this is what is sent to my addCombo method. It means I have to essentially repeat code, which I dont like doing but it means the addCombo() method works as required and keeps the code easier to understand by not introducing difficult syntax.

public enum RenameFileOptions implements OptionList
{
    NO(TextLabel.RENAME_FILE_OPTION_NO),
    YES_IF_MATCHED_TO_RELEASE(TextLabel.RENAME_FILE_OPTION_YES_IF_RELEASE_MATCH),
    YES_IF_MATCHED_TO_RELEASE_OR_SONG(TextLabel.RENAME_FILE_OPTION_YES_IF_RELEASE_OR_SONG_MATCH),
    YES_IF_HAS_BASIC_METADATA(TextLabel.RENAME_FILE_OPTION_YES_IF_HAS_METADATA),
    YES_FOR_ALL_SONGS(TextLabel.RENAME_FILE_OPTION_YES),

    ;
    private TextLabel label;

    RenameFileOptions(TextLabel label)
    {
        this.label=label;
    }

    public String getName()
    {
        return label.getMsg();
    }

    public String toString()
    {
        return getName();
    }

    public static List<NameKey> getOptions()
    {
        List<NameKey> options = new ArrayList<NameKey>();
        for(RenameFileOptions next:RenameFileOptions.values())
        {
            options.add(new NameKey(next.ordinal(), next.getName()));
        }
        return options;
    }
}

public class NameKey
{
    private Integer id;
    private String name;

    public NameKey(Integer id, String name)
    {
        this.id =id;
        this.name=name;
    }
    public Integer getId()
    {
        return id;
    }

    public void setId(Integer id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }
}

You should use Class.getEnumConstants() method.

So, middle part of your code should be something like

                each(Arrays.asList(enumClass.getEnumConstants()),
                        next ->
                            iffElse(next.ordinal()==selectedValue,
                                    option(next.name()).attr(Html.SELECTED, Html.SELECTED).withValue(String.valueOf(next.ordinal())),
                                    option(next.name()).withValue(String.valueOf(next.ordinal()))
                            )
                ))

and you should pass Class<? extends Enum<?>> enumClass Class<? extends Enum<?>> enumClass in method parameters.

You can use EnumSet.allOf() :

for(MyType t : EnumSet.allOf(MyType.class)) {
    doSomethingWith(t);
}

... or with Java 8 lambdas:

EnumSet.allOf(MyType.class).forEach( 
    t -> doSomethingWith(t)
);

Despite being a Set , EnumSet 's documentation states that its iterator yields values "in their natural order (the order in which the enum constants are declared)"


For an arbitarary enum class:

<T extends Enum<T>> void loopAroundEnum(Class<T> enumType) {
    EnumSet.allOf(enumType).forEach(
       val -> doSomethingWith(val) // val is of type T
    );
}

Although the Java habit is to not optimise prematurely, it's worth knowing that an EnumSet is probably more efficient both in speed and in memory consumption than using the MyType[] array returned by MyType.getEnumConstants() .

From EnumSet 's Javadoc:

Enum sets are represented internally as bit vectors. This representation is extremely compact and efficient. The space and time performance of this class should be good enough to allow its use as a high-quality, typesafe alternative to traditional int-based "bit flags."

As Enum is the base class, and you need to pass a Class to an enum:

public <E extends Enum<E>> void method(Class<E> type) {
    E[] values = type.getEnumConstants();
}

Of course Class has a test whether it is an enum; it returns null when no enum class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM