首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >分类列表的最佳方法

分类列表的最佳方法
EN

Stack Overflow用户
提问于 2019-05-25 12:27:48
回答 5查看 240关注 0票数 1

我有一个订单对象

代码语言:javascript
复制
public class Order{
  private Date orderDate;
  //other fields + getters & setters
}

以及订单列表(List< Orders>)。现在,我想根据类似的orderDate (这里类似的意思是,相同的年份、月份和日数)将此订单列表分组,并生成如下地图:

代码语言:javascript
复制
Map<Date, List<Order>> orderMap = new HashMap<>();

如何在Java 8+中做到这一点?

请注意,我们可能有相似的日期,但时间戳不同,这意味着我们希望以“年、月、日”为基础。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2019-05-25 15:53:14

tl;dr

作为你的Map< LocalDate , List< Order> >的钥匙

代码语言:javascript
复制
    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.

保留您的Date成员

如果不能从可怕的orderDate类中更改java.util.Date成员变量的类型,那么在java.time中执行业务逻辑。使用添加到旧类的新方法转换为/从Date转换。

不要使用LocalDateTime

在其他答案中已经讨论过使用java.time,但是那些使用错误类的是:LocalDateTime。这完全是错误的类使用,因为它不代表一个时刻。它代表了全球时区范围约26-27小时的潜在时刻。这个类拥有一个日期和一天的时间,但没有时区的概念或与世界协调时相抵消的概念。因此,如果一个LocalDateTime物体在今年1月23日下午12点举行,我们不知道那是东京的中午,加尔各答的中午,巴黎的中午,或者蒙特雷的中午--所有的时刻,相隔几个小时都是非常不同的时刻。

要表示某一时刻,请使用以下内容之一:

  • Instant 在世界协调时的一个时刻
  • OffsetDateTime 与世界协调时相抵消的时刻,一些小时-分钟-秒。
  • ZonedDateTime 通过特定区域的人使用的偏移量所看到的时刻,该时区具有Continent/Region格式的名称。

DateInstant

java.util.Date的替代品是java.time.Instant。两者都代表了UTC中的一个时刻,尽管Instant纳秒的分辨率比毫秒更高。

代码语言:javascript
复制
Instant instant = orderDate.toInstant() ;

时区

调整从UTC到您想要的时区。你想知道在加州巴斯托看到的日期吗?使用America/Los_Angeles时区。应用ZoneId来获得ZonedDateTime。此ZonedDateTime表示与Instant相同的时间点、时间线上的相同点,但使用的是不同的挂钟时间。

Continent/Region格式指定Continent/Region,如America/MontrealAfrica/CasablancaPacific/Auckland。不要使用2-4字母的缩写,如ESTIST,因为它们不是真正的时区,不标准化,甚至不是唯一的(!)。

请注意,java.time按设计使用不可变对象螺纹安全进行了分类。因此,您可以定义这个ZoneId一次,并保持它的周围,以便重用,甚至跨线程。

代码语言:javascript
复制
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, different wall-clock-time.

LocalDate

提取日期的部分,没有时间的一天和没有时区.

代码语言:javascript
复制
LocalDate ld = zdt.toLocalDate() ;  // The date as seen for this moment in Barstow, California.

使用LocalDate作为Map< LocalDate , List< Order> >的密钥。

Date成员更改为Instant

如何在Java 8+中做到这一点?

最好将代码从可怕的遗留日期-时间类迁移到现代的java.time类。Sun、Oracle和JCP社区在采用JSR 310时放弃了旧类。所以你应该.他们真的那么糟糕。

通常最好的后端工作,思考,存储和交换日期-时间值的UTC.仅将时区应用于(a)对用户的表示,(b)如果业务逻辑需要的话。

代码语言:javascript
复制
public class Order{
  private Instant whenOrdered ;
  //other fields + getters & setters
}

应用上面看到的相同的时区调整逻辑,得到一个LocalDate作为Map< LocalDate , List< Order > >的关键。

在用户喜欢的时区中向用户显示Instant。让java.time 自动本地化显示文本。

代码语言:javascript
复制
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.
    ) 
;

如果您只关心日期,而不关心一天的时间,并且不关心跨时区确定日期的模糊性(您在本地的一个小企业中),那么请使用LocalDate

代码语言:javascript
复制
public class Order{
  private LocalDate dateOrdered ;
  //other fields + getters & setters
}

关于java.time

http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html框架内置到Java8和更高版本中。这些类取代了麻烦的旧遗赠日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见http://docs.oracle.com/javase/tutorial/datetime/TOC.html。并搜索堆栈溢出以获得许多示例和解释。规范是JSR 310

http://www.joda.org/joda-time/项目现在在维护模式中,建议迁移到java.time类。

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC 4.2。不需要字符串,也不需要java.sql.*类。

在哪里获得java.time类?

  • Java 8Java 9Java 10Java 11和更高版本--捆绑实现的标准Java的一部分。
    • Java 9添加了一些次要的特性和修复。

  • Java 6Java 7
    • 大多数java.time功能都是在http://www.threeten.org/threetenbp/中移植到Java6&7中的。

  • 安卓
    • 较晚版本的Android实现的java.time类。
    • 对于早期的Android (<26),https://github.com/JakeWharton/ThreeTenABP项目采用了http://www.threeten.org/threetenbp/ (上面提到的)。见http://stackoverflow.com/q/38922754/642706

三次-额外项目使用其他类扩展java.time。这个项目是将来可能加入java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter更多

票数 2
EN

Stack Overflow用户

发布于 2019-05-25 13:09:19

由于不推荐使用Date类并保存实际日期和时间,所以可以在Order类中使用LocalDateTime作为字段。然后,您可以根据从LocalDate获得的LocalDateTime对订单进行分组:

代码语言:javascript
复制
List<Order> list = new LinkedList<>();

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

LocalDate在没有时间的情况下举行年度、月和日。

票数 3
EN

Stack Overflow用户

发布于 2019-05-25 13:07:32

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

代码语言:javascript
复制
public class Order{
  private Date orderDate;
  //other fields + getters & setters
  public String getStringDate(){
     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
     return dateFormat.format(this.orderDate);
  }
}

然后在上面分组:

代码语言:javascript
复制
Map<String, List<Order>> ordersWithSimilarOrderDate = orders.stream().collect(Collectors.groupingBy(Order::getStringDate));
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56304807

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档