Java 对列表进行分类的最佳方法

Java 对列表进行分类的最佳方法,java,collections,Java,Collections,我有一个订单对象 public class Order{ private Date orderDate; //other fields + getters & setters } 和订单列表(List)。现在,我想根据相似的orderDate(此处相似的意思是同一年、同一月、同一天)对该订单列表进行分组,并生成如下地图: Map<Date, List<Order>> orderMap = new HashMap<>(); Map order

我有一个订单对象

public class Order{
  private Date orderDate;
  //other fields + getters & setters
}
和订单列表(List)。现在,我想根据相似的orderDate(此处相似的意思是同一年、同一月、同一天)对该订单列表进行分组,并生成如下地图:

Map<Date, List<Order>> orderMap = new HashMap<>();
Map orderMap=newhashmap();
如何在Java8+中实现这一点

请注意,我们可能有相似的日期,但不同的时间戳,这意味着我们 想根据“年、月、日”来计算吗


您可以创建一个返回订单“相似性”的方法,例如:

公共类秩序{
私有日期orderDate;
//其他字段+getter和setter
公共字符串getStringDate(){
SimpleDataFormat dateFormat=新的SimpleDataFormat(“yyyy/MM/dd”);
return dateFormat.format(this.orderDate);
}
}
然后对其进行分组:

Map ordersWithSimilarOrderDate=orders.stream().collect(Collectors.groupingBy(Order::getStringDate));

您可以创建一个返回订单“相似性”的方法,例如:

公共类秩序{
私有日期orderDate;
//其他字段+getter和setter
公共字符串getStringDate(){
SimpleDataFormat dateFormat=新的SimpleDataFormat(“yyyy/MM/dd”);
return dateFormat.format(this.orderDate);
}
}
然后对其进行分组:

Map ordersWithSimilarOrderDate=orders.stream().collect(Collectors.groupingBy(Order::getStringDate));

由于
Date
类已被弃用并保存实际日期和时间,您可以使用
LocalDateTime
作为
Order
类中的字段。然后,您可以根据取自
LocalDateTime
LocalDate
对订单进行分组:

List<Order> list = new LinkedList<>();

Map<LocalDate, List<Order>> collect = list.stream()
                .collect(Collectors.groupingBy(order -> order.getOrderDate().toLocalDate()));
List List=newlinkedlist();
Map collect=list.stream()
.collect(Collectors.groupingBy(order->order.getOrderDate().toLocalDate());

保存没有时间的年、月和日。

由于
Date
类已被弃用并保存实际日期和时间,您可以使用
LocalDateTime
作为
Order
类中的字段。然后,您可以根据取自
LocalDateTime
LocalDate
对订单进行分组:

List<Order> list = new LinkedList<>();

Map<LocalDate, List<Order>> collect = list.stream()
                .collect(Collectors.groupingBy(order -> order.getOrderDate().toLocalDate()));
List List=newlinkedlist();
Map collect=list.stream()
.collect(Collectors.groupingBy(order->order.getOrderDate().toLocalDate());

可以无时间地保存年、月、日。

我并不支持使用流做任何事情,但你可以做到 以一种艰难的转换方式

List orders=。。。你的名单。。。
Map orderMap=orders.stream().collect(收集器)groupingBy(订单->{
//从日期转换为即时
Instant dateInstant=order.getOrderDate().toInstant();
//将Instant转换为LocalDateTime并将其设置为一天的开始
LocalDateTime dateTime=dateInstant.atZone(ZoneId.systemDefault()).toLocalDate().atStartOfDay();
//将其转换回瞬间
Instant startOfDayInstant=dateTime.atZone(ZoneId.systemDefault()).toInstant();
//返回util日期
返回日期。起始日期(startOfDayInstant);
}));

这是在您需要util date的情况下。否则,我支持michalk的答案,我并不支持用流做任何事情,但你可以做到 以一种艰难的转换方式

List orders=。。。你的名单。。。
Map orderMap=orders.stream().collect(收集器)groupingBy(订单->{
//从日期转换为即时
Instant dateInstant=order.getOrderDate().toInstant();
//将Instant转换为LocalDateTime并将其设置为一天的开始
LocalDateTime dateTime=dateInstant.atZone(ZoneId.systemDefault()).toLocalDate().atStartOfDay();
//将其转换回瞬间
Instant startOfDayInstant=dateTime.atZone(ZoneId.systemDefault()).toInstant();
//返回util日期
返回日期。起始日期(startOfDayInstant);
}));

这是在您需要util date的情况下。否则,我支持michalk的答案,如果您必须使用
Date
,您仍然可以通过提供时区信息将其转换为
LocalDate

Map<LocalDate, List<Order>> collect =
    list.stream().collect(Collectors.groupingBy(order -> 
        order.getOrderDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()));
地图收集=
list.stream().collect(收集器.groupingBy(订单->
order.getOrderDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());

如果必须使用
Date
,您仍然可以通过提供时区信息将其转换为
LocalDate

Map<LocalDate, List<Order>> collect =
    list.stream().collect(Collectors.groupingBy(order -> 
        order.getOrderDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()));
地图收集=
list.stream().collect(收集器.groupingBy(订单->
order.getOrderDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
tl;博士 作为
映射

    order
    .getDate()                                  // Accessor method to retrieve your `java.util.Date` object.
    .toInstant()                                // Convert from terrible legacy class `Date` to modern `java.time.Instant` class. Both represent a moment in UTC.
    .atZone(                                    // Adjust from UTC to the time zone used by your business.
            ZoneId.of( "America/Los_Angeles" ) 
    )                                           // Remember: For any given moment, the date varies around globe by time zone, “tomorrow” in Tokyo while “yesterday” in Montréal. 
    .toLocalDate()                              // Extract the date-only portion, without time-of-day, without time zone, to use as the key in our map.
保留您的
日期
会员 如果无法从java.util.Date类中更改
orderDate
成员变量的类型,请使用java.time执行业务逻辑。使用添加到旧类中的新方法将日期转换为日期

不要使用
LocalDateTime
其他答案中已经讨论了使用java.time,但这些答案使用了错误的类:。这完全是错误的类,因为它并不代表一个时刻。它代表了大约26-27小时范围内的潜在时刻,即全球时区的范围。该类包含日期和时间,但没有时区或UTC偏移量的概念。因此,如果一个
LocalDateTime
对象在今年1月23日下午12点运行,我们不知道这是东京的中午、加尔各答的中午、巴黎的中午还是蒙特勒尔的中午——所有这些都是非常不同的时刻,相隔几个小时

要表示某个时刻,请使用以下选项之一:

  • 瞬间

    UTC中的瞬间
  • OffsetDateTime

    与UTC偏移的时刻,以小时分秒为单位
  • ZonedDateTime

    一瞬间
    LocalDate ld = zdt.toLocalDate() ;  // The date as seen for this moment in Barstow, California.
    
    public class Order{
      private Instant whenOrdered ;
      //other fields + getters & setters
    }
    
    Locale locale = new Locale( "fr" , "TN" ) ;      // French in Tunisia.
    ZoneId userZone = ZoneId.of( "Africa/Tunis" ) ;  // Or ZoneId.systemDefault() to get the JVM’s current default time zone (appropriate to a client machine, but not a server machine). 
    String outputForDisplay = 
        order
        .whenOrdered
        .atZone( userZone )                          // Adjust from UTC to time zone, going from `Instant` to `ZonedDateTime`. 
        .format(                                     // Generate text representing the value inside our `ZonedDateTime` object.
            DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG )  // Let java.time automatically localize, rather than hard-code a formatting pattern.
        ) 
    ;
    
    public class Order{
      private LocalDate dateOrdered ;
      //other fields + getters & setters
    }