A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小刀葛小伦 于 2019-6-13 12:35 编辑

小花:Hey,Morty。最近正在准备面试,你说Java8 的新特性会不会考到呢?
我:Java8 14年3月份就出了,到现在已经有很长的一段发展时间了。但是根据我的面试经验,在笔试题的部分应该不会直接让你写出Java8 的解决方案,倒是会在面试的过程中由技术官提问一些比较重要的Java 8 特性。
小花:哦,那Java 8 有什么在开发中经常会用到的特性呢?
我:有很多啊,其中一个就是为了解决广遭诟病的Java日期操作而推出的“时间日期API”。
小花:哦?Java8 原来还有这么个好东西?以前处理日期和时间的时候,总是感觉很别扭。
我:是的呢。在Java8 以前,我们处理时间或者格式化都是通过 java.util.Date 和java.text.DateFormat。这在操作的时候有诸多的不便,在实际生产开发中很容易受到限制。
首先,Date类本身是可变类型,而SimpleDateFormat也不是线程安全的。这一点在并发编程的时候就不得不认真考虑。而在Java8中,不仅改善了日期类型的线程安全性,将java.time包下所有的 API 如LocalDateTime、DateTimeFormatter都设置为了final的,而且也添加了更加丰富的日期处理功能,比如比较两个时间大小;计算一天后、一天前,或者一周后、一周前的日期等等。甚至判断闰年也都是现成的接口。
小花:天哪,用了这么久java8,居然都不知道还有这么神奇的玩意。前阵子和其他公司对接接口,日期这部分着实费了不少力气,早知道Java8的日期API这么强大,我就不用掉这么多头发了,呜呜呜~~~

我:恩,是的呢。
小花:那我们在日期与字符串相互转化的时候,应该怎样用Java8 来描述呢?
我:恩,日期和字符串的相互转化的确是常见的场景。不过先不着急,来看看在Java8中如何获取当前时间吧:
[Java] 纯文本查看 复制代码
LocalDateTime now = LocalDateTime.now();
//output : 2019-06-06T14:16:05.323
[align=left]
小花:咦?感觉代码可读性更强了一些,不过输出的时候为什么中间会带一个大T呢?而且也不用 format 直接就显示成了爱情的模样!
我:哈哈,你还真皮。大T是因为LocalDateTime 的toString方法遵循ISO-8601的国际标准,你可以上网百度一下这个标准,简单的说就是在日期和时间组合显示的时候,中间要加个'T',具体原因我也没有联系过相关负责人,不过根据我的经验,很可能是因为空格的话在信息传输的过程中,由于不可见字符造成一些编码的错误,这在Base64编码中有过相关的描述。
另外,不仅LocalDateTime重写了toString,其他的比如DateTime都完成了最常用的文本描述形式。因为在大多数情况,人们只需要yyyy-MM-dd HH:mm:ss的形式而不需要像:Tue Jun 04 07:20:19 CST 2019,这样。
小花:就是嘛,new Date()之后每次都要format,真的没必要。
我:Java8 中也提供了日期的字符串格式化,而且都是静态方法,相比java.util,这套API可真是做到了完全的工具化处理。
[Java] 纯文本查看 复制代码
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String nowStr = now.format(formatter);
// output : 2019-06-06 14:37:32
[align=left]

你可以像上面这样直接来格式化日期类型的对象,但是要注意,LocalDate只包含日期,LocalTime只包含时间,如果你的 pattern 串中无法与之匹配,就会报:UnsupportedTemporalTypeException异常。举个栗子:
[Java] 纯文本查看 复制代码
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalTime now = LocalTime.now(); // 只获取时间的封装
System.out.println(formatter.format(now)); //异常

小花:还真是把双刃剑!

我:嗯嗯,java8日期API将日期、时间、日期加时间进行了细分,操作更灵活,但同时也需要小心处理。其实如果你用惯了java.util.Date,你只需要直接使用LocalDateTime就可以了,形式上它和Date本身都是日期加时间的组合版,而且,如果你看到LocalDateTime的源码的话,一定很吃惊,因为它完全就是调用的LocalDate和LocalTime的接口,换句话说,它只是把这两个类型有机组合之后的封装API。
接下来,我们我们来聊聊比较有意思的场景吧。
小花:嗯,我想表示具体某一天的日期,应该如何获取到日期对象呢?
我:如果你心里有一个具体的日期,或者时间,可以直接这样写:
[Java] 纯文本查看 复制代码
LocalDateTime nationalDay = LocalDateTime.of(2019, Month.OCTOBER, 1, 0, 0);
// output : 2019-10-01T00:00
如果只需要日期就可以把LocalDateTime 换成LocalDate,并去掉参数中的时和分。如果只是一个日期字符串,可以利用DateTimeFormatter:
[Java] 纯文本查看 复制代码
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime someDay = LocalDateTime.parse("2019-10-01 14:30:30", formatter);
// output : 2019-10-01T14:30:30
小花:我这里有两个日期,但是如何优雅地比较大小呢?
我:没有比直接调用API更优雅的事情了:
[Java] 纯文本查看 复制代码
//nationalDay == 2019-10-01T00:00
boolean nowIsBefore = LocalDateTime.now().isBefore(nationalDay);
小花:如果我不仅要比较大小,还要知道两个日期之间相差多长时间呢?
我:不论是相差的年、月、日、时、分、秒,都是可以的:
[Java] 纯文本查看 复制代码
long diffYears = ChronoUnit.YEARS.between(LocalDateTime.now(), nationalDay);
// output : 0
long diffMonths = ChronoUnit.MONTHS.between(LocalDateTime.now(), nationalDay);
// output : 3
long diffDays = ChronoUnit.DAYS.between(LocalDateTime.now(), nationalDay);
// output : 118
long diffHours = ChronoUnit.HOURS.between(LocalDateTime.now(), nationalDay);
// output : 2847
long diffMins = ChronoUnit.MINUTES.between(LocalDateTime.now(), nationalDay);
// output :170878
long diffSecs = ChronoUnit.SECONDS.between(LocalDateTime.now(), nationalDay);
// output : 10252739
小花:那我想获取当前分钟数呢?
我:这可要分两种情况了,一种是一天之中的分钟数,一种是一小时之中的分钟数。如果你这么写:

[Java] 纯文本查看 复制代码
int mins = LocalDateTime.now().getMinute();

那么默认获取小时之内的分钟数,不过还有一种更万金油的方式,不论你是一天之内还是一小时之内:
[Java] 纯文本查看 复制代码
long minsOfHour = LocalDateTime.now().getLong(ChronoField.MINUTE_OF_HOUR);
long minsOfDay = LocalDateTime.now().getLong(ChronoField.MINUTE_OF_DAY);

小花:啊,真是厉害,我能想到的场景就这些了。你还有什么补充吗?
我:来介绍两个有意思的枚举:Month、DayOfWeek,如果你已经有了一个LocalDateTime类型的对象,比如sunDay。你想知道它是星期几,那么你可以这么写:
[Java] 纯文本查看 复制代码
DayOfWeek dayOfWeek = sunDay.getDayOfWeek();
// output : SUNDAY
int dayOfWeek = sunDay.getDayOfWeek().getValue();
// output : 7
想知道月份的话,就可以这么写:
[Java] 纯文本查看 复制代码
Month month = LocalDateTime.now().getMonth();
// output : JUNE
int month2 = LocalDateTime.now().getMonth().getValue();
// output : 6
小花:哦,对了,前面你说的可以直接判断闰年,怎么写呢?
我:哈哈,你还记着啊,我差点都忘了。判断闰年还是平年,你可以直接调用日期对象的isLeapYear方法:
[Java] 纯文本查看 复制代码
LocalDate today = LocalDate.now();
boolean leapYear = today.isLeapYear(); // output : false

小花:哇,Java8的这套日期API真是太好用了。

我:是的,Java8的日期API真的是功能强大,我们刚才聊过的这些都是日常开发中非常常用的场景。另外还有一些时区的处理方法,不过这些问题都要进国际大公司,平时需要处理跨时区的问题时才能遇得上了。这里就不做过多的讨论了。
综上,就是小编总结的Java 8 时间日期API的常见用法,希望各位看官喜欢。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马