Luis Durazo Luis Durazo - 5 months ago 10
Java Question

Iterate Enum by argument

I have the following enum, but i want to iterate over the second argument only without having to iterate over the enum member that are outside of this category, so if i have a

message
:"Message" and category
"Category"
i can specify the category as argument too in the method
isMessageInGroup
without having to iterate over those with another category like
MESSAGE_3
:"Another Category"

Is there a neat way to do it and save some iteration time? probably not even with a great deal of values this will affect performance noticeably, but i want to know if it possible. Searched for a bit but hard to find this specific question.

The Enum below does charge for messages by category but i want to know if i can avoid iterating over those outside the category wanted

public enum MessagesEnum {
MESSAGE_1("Message", "Category"),
MESSAGE_2("Another Message", "Category"),
MESSAGE_3("Odd Message", "Another Category");

private final String message;
private final String category;

SabreErrorMessages(String message, String errorCategory) {
this.message = message;
this.category = category;
}

public String getMessage() {
return message;
}

public String getCategory() {
return category;
}

public static boolean isMessageInGroup(String message){
for(MessagesEnum message : MessagesEnum.values()) {
if(message.contains(message.getMessage()) && message.getCategory().equals("Category")) {
return true;
}
}
return false;
}
}

Answer

As the comments have said, an out-of-the-box enum won't be most efficient for this because you will have to use an iterator. HashMap, however, provides O(1) lookup on average and will be much faster.

public enum Messages {

    MESSAGE_1("Message", "Category"),
    MESSAGE_2("Another Message", "Category"),
    MESSAGE_3("Odd Message", "Another Category");

    private static final Map<String, Set<String>> map = new HashMap<>();
    static {
        for (Messages m : Messages.values()) {
            map.computeIfAbsent(m.category, s -> new HashSet<>()).add(m.message);
        }
    }

    private final String message, category;

    private Messages(String message, String category) {
        this.message = message;
        this.category = category;
    }

    public String getMessage() { return message; }
    public String getCategory() { return category; }

    public static boolean isMessageInGroup(String message){
        // use `getOrDefault` if `get` could return null!!
        return map.get("Category").contains(message);
    }
}

Ideone Demo

Edit: Should you choose to implement a method like messagesInGroup, the safest way would be to implement it using an unmodifiable Set so as to protect the integrity of the enum's internals.

public static Set<String> messagesInGroup(String category) {
    return Collections.unmodifiableSet(
        map.getOrDefault(category, new HashSet<>())
    );
}
Comments