Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Highest ordinal enum value

Tags:

java

enums

java-8

I'm looking to compute the highest ordinal enum value from a list of enum properties in a list of beans.

For example, I have:

@Data
public class MyBean {
    private Priority priority;
}

and

public enum Priority {
    URGENT("Urgent"),
    HIGH("High"),
    MEDIUM("Medium"),
    LOW("Low");

    @Getter
    private final String value;

    Priority(String value) {

        this.value = value;
    }

    @Override
    public String toString() {

        return getValue();
    }
}

If I have a Listof MyBeans, how can I find the max ordinal value of the bean's priority in the list?

Example:

   {myBean1, myBean2, myBean3, myBean4} where

    myBean1.getPriority() = Priority.LOW
    myBean2.getPriority() = Priority.URGENT
    myBean3.getPriority() = Priority.HIGH
    myBean4.getPriority() = null

    returns Priority.URGENT

I'm thinking the worst case is that I could iterate the values() in the enum starting with Collections.min(Arrays.asList(Priority.values())); and loop through each bean to see whether the value matches. But this seems tedious.

like image 881
vphilipnyc Avatar asked May 18 '26 09:05

vphilipnyc


2 Answers

You can use the Stream API and especially the max(Comparator) method to find the bean with the highest priority.

Note: your enum has the priorities in reverse ordinal order. In my example, I will assume the opposite to make the code more self-explanatory. Switch max for min and nullsFirst with nullsLast, if you do not re-arrange your enum.

Bean highest = beans.stream()
                    .max(Comparator.comparing(Bean::getPriority,
                                              Comparator.nullsFirst(Comparator.comparing(Priority::ordinal))))
                    .orElse(null);

return highest.getPriority();

If you only need the priority, you can simplify:

return beans.stream()
            .map(Bean::getPriority)
            .filter(Objects::nonNull)
            .max(Comparator.comparing(Enum::ordinal))
            .orElse(null);

It works as follows:

  1. Look at every bean
  2. Take its priority
  3. Discard null priorities
  4. Pick the maximum priority
  5. Beware of the list being empty or all priorities being null

Note: My examples are very verbose. shmosel's (deleted) answer shows that you can order enums naturally by ordinal, making for nicer comparators. Comparator.comparing(Enum::ordinal) can just become Comparator.naturalOrder().

like image 59
Malte Hartwig Avatar answered May 20 '26 22:05

Malte Hartwig


I would give each priority a specific numeric value and add a method which can compare them. Unfortunately enums can't implement Comparable (for consistency) which is a bit of a bummer here.

The fact that you are returning null sentinel values complicates things slightly. I would rethink this if I were you. Consider a "Default" priority instead which can act as our priority if one is missing.

I've added the default priority as a totally unique option, but depending on what you want you could just use medium or low as the default.

public enum Priority {
    URGENT ("Urgent", 10),
    HIGH   ("High",    5),
    MEDIUM ("Medium",  2),
    LOW    ("Low",     0),
    DEFAULT("Default",-1);

    @Getter
    private final String name;

    private final int value;

    Priority(String name, int value) {
        this.name  = name;
        this.value = value;
    }

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

    public int compare(Priority that) {
        return Integer.compare(this.value, that.value);
    }
}

You will then need to change your priority getter to return this new default rather than null, else we'll get null pointer exceptions later on.

public class MyBean {
    private Priority priority;

    // Never returns null :)
    public Priority getPriority() {
        return (priority != null) ? priority : Priority.DEFAULT;
    }
}

Now we've done the "hard" work, getting the highest priority is super easy:

Priority max = Collections.max(beans, (a,b) ->
    a.getPriority().compare(b.getPriority())
).getPriority();
like image 20
Michael Avatar answered May 20 '26 21:05

Michael