最高序数枚举值

时间:2017-05-09 22:25:26

标签: java enums java-8

我希望从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以查看值是否匹配。但这似乎很乏味。

4 个答案:

答案 0 :(得分:7)

您可以使用Stream API,尤其是max方法来查找优先级最高的bean。

注意:您的枚举具有反向顺序的优先级。在我的例子中,我将假设相反的方式使代码更加不言自明。如果您不重新安排枚举,请min nullsFirstnullsLast 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

它的工作原理如下:

  1. 看看每一个豆子
  2. 优先考虑
  3. 放弃空优先级
  4. 选择最高优先级
  5. 请注意列表为空或所有优先级为空
  6. 注意:我的例子非常详细。 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();