【问题标题】:Using Java Comparator for sorting using multiple fields based on condition使用 Java Comparator 根据条件使用多个字段进行排序
【发布时间】:2017-05-18 05:25:58
【问题描述】:

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

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

这里state字段的可能值为OPEN、PENDING、RUNNING、CLOSED、CANCELED等,其中OPEN、PENDING和RUNNING为Active状态。现在我想编写对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;
    }
});

我的问题是我上面的单个比较器的实现是否好?或者有更好的方法吗? 很可能我必须坚持使用 Java 7,但也欢迎使用 Java 8 的解决方案。

【问题讨论】:

  • 问题:为什么你的活动状态是一个字符串?枚举在这里不是更合适吗?
  • 顺便说一句:我对您的实施没有意见,但您最好等待更专业的人来充分权衡。
  • @HovercraftFullOfEels,不幸的是我无法对MyClass 进行任何更改,因为我们不拥有它,只是简单地使用它。可能我需要请相应的团队进行枚举。

标签: java sorting collections filter comparator


【解决方案1】:

在 Java 8 中,我认为使用 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;
    }
}

在 Java 7 中,假设类路径中有 Guava,则可以使用 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();

【讨论】:

  • Java 7 中是否有类似的功能?不过这很好。 +1
  • 这里的日期将如何比较?在我的解决方案中,我使用的是 DateTimeComparator。如果日期是 joda 时间,他将在这里使用什么?
  • 您可以将 DateTimeComparator 作为第二个参数传递给 thenComparing。查看更新的代码。
  • 我不认为在 Java 7 中没有使用 Guava 或其他库的特别优雅的解决方案。
  • 我在 Java 7 中添加了一个示例,但不幸的是它需要 Guava。
猜你喜欢
  • 2019-04-07
  • 2021-11-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-19
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多