基本上,我有一个对象的数组列表,这些对象具有名称和startDate,并且它们的初始顺序类似于:

弗兰克1990年10月20日

1990年1月2日的法案

弗兰克2/2/1990

约翰1990年9月8日

1990年4月4日法案

弗兰克1990年5月1日

我想按声明的名字顺序打印,然后按日期打印,例如,最终打印应打印:

弗兰克1990年1月1日

弗兰克1990年5月1日

弗兰克1990年10月20日

1990年1月2日的法案

1990年4月4日法案

约翰1990年9月8日

最佳答案

假设您的对象类如下所示:

private static class MyObject {

  private final String name;
  private final Date date;

  private MyObject(String name, Date date) {
    this.name = name;
    this.date = date;
  }

  public String getName() {
    return name;
  }

  public Date getDate() {
    return date;
  }
}


您可以使用以下方法打印对象:

@Test
public void printInOrder() {
  List<MyObject> list = new ArrayList<>(); // List containing your objects
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 10, 20).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 1, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 2, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("John", Date.from(LocalDate.of(1990, 9, 8).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 4, 4).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 5, 1).atStartOfDay(ZoneId.systemDefault()).toInstant())));

  list.stream()
      .sorted(Comparator.comparing(MyObject::getName)
                        .thenComparing(Comparator.comparing(MyObject::getDate)))
      .map(obj -> obj.getName() + " " + obj.getDate())
      .forEach(System.out::println);
}


输出:


  Bill Tue Jan 02 00:00:00 CET 1990
  1990年4月4日星期三00:00:00比尔
  1990年2月2日星期五星期五欧洲中部时间
  1990年5月1日星期二美国东部时间弗兰克(Frank Tue)
  1990年10月20日,星期六ET CET
  John Sat 1990年9月8日00:00:00




它使用Java 8流和比较器链对对象进行排序。比较器按给定属性进行比较,thenComparing用于链接它们。



更新:

由于不确定我是否可能误解了您,因此以下是以下情况的第二种版本:

您想按名称排序,但是名称会按顺序出现在原始列表中,因此名称将首先出现。

在这种情况下,您将必须记住一个单独的临时列表中的名称顺序(仅按原始顺序包含唯一名称),之后可以在比较器中使用它们。

通过将原始列表转换为一个集合(因此只有唯一的名称),然后将此集合转换回一个列表(以便能够在比较器中使用indexOf)来生成此列表。

@Test
public void printInOrder() {
  List<MyObject> list = new ArrayList<>();
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 10, 20).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 1, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 2, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("John", Date.from(LocalDate.of(1990, 9, 8).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 4, 4).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 5, 1).atStartOfDay(ZoneId.systemDefault()).toInstant())));

  List<String> declaredNameOrder = new ArrayList<>(list.stream()
                                      .map(MyObject::getName)
                                      .collect(Collectors.toCollection(LinkedHashSet::new)));

  list.stream()
      .sorted(Comparator.<MyObject>comparingInt(o -> declaredNameOrder.indexOf(o.getName()))
                  .thenComparing(Comparator.comparing(MyObject::getDate)))
      .map(obj -> obj.getName() + " " + obj.getDate())
      .forEach(System.out::println);
}


输出:


  1990年2月2日星期五星期五欧洲中部时间
  1990年5月1日星期二美国东部时间弗兰克(Frank Tue)
  1990年10月20日,星期六ET CET
  Bill Tue Jan 02 00:00:00 CET 1990
  1990年4月4日星期三00:00:00比尔
  John Sat 1990年9月8日00:00:00

10-08 18:58