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.
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:
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().
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With