最高序数枚举值

vph*_*nyc 2 java enums java-8

我想从bean列表中的枚举属性列表中计算最高序数枚举值.

例如,我有:

@Data
public class MyBean {
    private Priority priority;
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我有一个ListMyBeans,我怎么能找到bean的的最大序号值priority列表中?

例:

   {myBean1, myBean2, myBean3, myBean4} where

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

    returns Priority.URGENT
Run Code Online (Sandbox Code Playgroud)

我认为最糟糕的情况是我可以values()在枚举中迭代Collections.min(Arrays.asList(Priority.values()));并循环遍历每个bean以查看值是否匹配.但这似乎很乏味.

Mal*_*wig 8

您可以使用Stream API,尤其是max(Comparator)方法来查找具有最高优先级的bean.

注意:您的枚举具有反向顺序的优先级.在我的例子中,我将假设相反的方式使代码更加不言自明.切换maxminnullsFirstnullsLast,如果不重新安排你的枚举.

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

return highest.getPriority();
Run Code Online (Sandbox Code Playgroud)

如果您只需要优先级,则可以简化:

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

它的工作原理如下:

  1. 看看每一个豆子
  2. 优先考虑
  3. 丢弃空优先级
  4. 选择最高优先级
  5. 请注意列表为空或所有优先级为空

注意:我的例子非常详细.shmosel(删除)的答案表明你可以自然地订购枚举ordinal,制作更好的比较器. Comparator.comparing(Enum::ordinal)可以成为Comparator.naturalOrder().

  • 好吧,我个人认为流可以让很多东西更容易理解(一旦你习惯阅读它们),因为几乎每个单词都有意义.当然,每个人都知道如何使用经典的局部变量/ for循环方式实现它,但它是需要阅读的样板,以确保它真的只是样板而没有"隐藏"的惊喜. (5认同)
  • 关于效率,我发现在我们的代码中很多地方使用流可以通过省略多个临时集合和变量的创建来抵消一些性能影响.根据用例,性能甚至可能不是问题.只要我没有处理大量数据或感受到压力,我总是追求可读性和可维护性. (3认同)
  • @Michael如果OP缺乏经验并且因为仅限代码的答案不受欢迎,这是一种礼貌.任何使用过流的人都可以很容易地阅读它.第二个例子尤其比等效循环更清晰. (2认同)

Mic*_*ael 5

我会给每个优先级一个特定的数值并添加一个可以比较它们的方法。不幸的是,枚举不能实现 Comparable(为了一致性),这在这里有点令人失望。

您返回空标记值的事实使事情稍微复杂化。如果我是你,我会重新考虑这一点。考虑一个“默认”优先级,如果缺少一个,它可以作为我们的优先级。

我已将默认优先级添加为一个完全独特的选项,但根据您的需要,您可以使用中或低作为默认值。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你需要改变你的优先级 getter 来返回这个新的默认值而不是null,否则我们稍后会得到空指针异常。

public class MyBean {
    private Priority priority;

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

现在我们已经完成了“艰苦”的工作,获得最高优先级非常容易:

Priority max = Collections.max(beans, (a,b) ->
    a.getPriority().compare(b.getPriority())
).getPriority();
Run Code Online (Sandbox Code Playgroud)

  • @MalteHartwig `Collections.max()` 并不新鲜。但值得注意的是,枚举实现了开箱即用的可比性;您不需要明确检查序数。 (2认同)
  • 您的比较逻辑不正确。如果 `a` 和 `b` 都为 null,则应该返回 0。 (2认同)
  • 您不应该破坏接口合同,即使它对于特定用例是安全的。 (2认同)