我希望从bean列表中的枚举属性列表中计算最高序数枚举值。
例如,我有:
@Data
public class MyBean {
private Priority priority;
}
和
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();
}
}
如果我有List
MyBeans
,如何找到列表中priority
的最大序号值?
示例:
{myBean1, myBean2, myBean3, myBean4} where
myBean1.getPriority() = Priority.LOW
myBean2.getPriority() = Priority.URGENT
myBean3.getPriority() = Priority.HIGH
myBean4.getPriority() = null
returns Priority.URGENT
我认为最糟糕的情况是我可以在values()
开始的枚举中迭代Collections.min(Arrays.asList(Priority.values()));
并循环遍历每个bean以查看值是否匹配。但这似乎很乏味。
答案 0 :(得分:7)
您可以使用Stream API,尤其是max
方法来查找优先级最高的bean。
注意:您的枚举具有反向顺序的优先级。在我的例子中,我将假设相反的方式使代码更加不言自明。如果您不重新安排枚举,请min
nullsFirst
和nullsLast
Bean highest = beans.stream()
.max(Comparator.comparing(Bean::getPriority,
Comparator.nullsFirst(Comparator.comparing(Priority::ordinal))))
.orElse(null);
return highest.getPriority();
。
return beans.stream()
.map(Bean::getPriority)
.filter(Objects::nonNull)
.max(Comparator.comparing(Enum::ordinal))
.orElse(null);
如果您只需要优先级,则可以简化:
ordinal
它的工作原理如下:
注意:我的例子非常详细。 shmosel的(已删除)答案显示您可以Comparator.comparing(Enum::ordinal)
自然地订购枚举,以便获得更好的比较器。 Comparator.naturalOrder()
可以成为currIndex: number = -1;
。
答案 1 :(得分:4)
我会给每个优先级一个特定的数值,并添加一个可以比较它们的方法。不幸的是,枚举无法实现Comparable(为了保持一致性),这在某种程度上是一种无赖。
您返回null哨兵值这一事实会使事情略微复杂化。如果我是你,我会重新考虑这个。考虑一个“默认”优先级,如果缺少一个优先级,它可以作为我们的优先级。
我已将默认优先级添加为完全唯一的选项,但根据您的需要,您可以使用中或低作为默认值。
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);
}
}
然后,您需要更改优先级获取器以返回此新默认值而不是null
,否则稍后我们将获得空指针异常。
public class MyBean {
private Priority priority;
// Never returns null :)
public Priority getPriority() {
return (priority != null) ? priority : Priority.DEFAULT;
}
}
现在我们已经完成了“艰苦”工作,获得最高优先级非常容易:
Priority max = Collections.max(beans, (a,b) ->
a.getPriority().compare(b.getPriority())
).getPriority();
答案 2 :(得分:3)
另一种安全的方法是使用guava中的Oridering
作为定义explicit
订单的方式,而不依赖于枚举ordinal
正如其他人指出的那样改变。
// creates an explicit Order (from left to right)
Ordering<Priority> order = Ordering.explicit(Priority.LOW,
Priority.MEDIUM,
Priority.HIGH,
Priority.URGENT)
.nullsFirst();
List<MyBean> list = Arrays.asList(new MyBean(Priority.HIGH),
new MyBean(null), new MyBean(Priority.URGENT));
Priority p = list.stream()
.map(MyBean::getPriority)
.max(order)
.orElse(null);
System.out.println(p); // Urgent
答案 3 :(得分:1)
您有一个MyBean
元素的列表,这些元素具有priority
属性,您还需要根据此优先级从该列表中获取最高元素。
如果您只需要执行一次,那么您可以使用Collections.max
使用合适的比较器,您将完成。
但是如果你需要多次获得这个最高元素,或者,如果获得这个最高元素后,你还需要获得第二高的元素,那么你可以完全使用PriorityQueue
:
Queue<MyBean> queue = new PriorityQueue<>(myComparator);
queue.addAll(myBeanList);
其中myBeanList
是包含所有MyBean
个实例的列表,myComparator
可根据您的要求定义如下:
Comparator<MyBean> myComparator = Comparator.comparing(
MyBean::getPriority,
Comparator.nullsLast(Comparator.naturalOrder()));
然后,您可以使用队列通过PriorityQueue.peek
方法获取具有最高优先级的元素:
MyBean highest = queue.peek();
这会获取但不会删除优先级最高的元素。
如果您想从队列中获取和删除元素,则应使用PriorityQueue.poll
方法:
MyBean highest = queue.poll();