有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用Java Comparator根据条件使用多个字段进行排序

我有一个关于有效使用Java Comparator的问题

class MyClass {
    //Active State: OPEN, PENDING, RUNNING
    private String state;
    private Date startDate;
    private Date endDate;
}

此处state字段的可能值为打开、挂起、运行、关闭、取消等,其中打开、挂起和运行为活动状态。现在我想写一个比较器,它对List<MyClass>进行排序,使活动的列在第一位,并按startDate排序,然后是根据endDate排序的非活动的列

static final Set<String> ACTIVE;// this set contains OPEN, PENDING, RUNNING

List<MyClass> myList;//This is my list
...
Collections.sort(myList, new Comparator<MyClass>() {
    @Override
    public int compare(MyClass o1, MyClass o2) {
        int c;
        boolean isO2 = ACTIVE.contains(o2.getState());
        boolean isO1 = ACTIVE.contains(o1.getState());
        if (isO2 && isO1) {
            c = DateTimeComparator.getInstance().compare(o2.getStartDate(), o1.getStartDate());
        } else if (isO2) {
            c = 1;
        } else if (isO1) {
            c = -1;
        } else {
            c = DateTimeComparator.getInstance().compare(o2.getEndDate(), o1.getEndDate());
        }
        return c;
    }
});

我的问题是我上面实现的有单比较器是否好?还是有更好的方法? 我很可能必须坚持使用Java7,但也欢迎使用Java8的解决方案


共 (1) 个答案

  1. # 1 楼答案

    在Java8中,我认为使用Comparator::comparing会更简洁一些。例如:

    Comparator<MyClass> comparator = Comparator.nullsFirst(Comparator.comparing((MyClass myClass) -> !isActive(myClass))
        .thenComparing((MyClass myClass) -> isActive(myClass) ? myClass.startDate : myClass.endDate, Comparator.nullsFirst(DateTimeComparator.getInstance())));
    
    private static boolean isActive(MyClass myClass)
    {
        switch (myClass.state)
        {
        case "OPEN":
        case "PENDING":
        case "RUNNING":
            return true;
        default:
            return false;
        }
    }
    

    在Java7中,假设类路径上有番石榴,可以使用Ordering。例如:

    Comparator<MyClass> comparator = Ordering.natural().reverse().onResultOf(new Function<MyClass, Boolean>() {
            @Override
            public Boolean apply(MyClass myClass) {
                return isActive(myClass);
            }
        })
        .compound(Ordering.from(DateTimeComparator.getInstance()).nullsFirst().onResultOf(new Function<MyClass, Date>() {
            @Override
            public Date apply(MyClass myClass) {
                return isActive(myClass) ? myClass.startDate : myClass.endDate;
            }
        }))
        .nullsFirst();