Java8 新增 DateTimeFormatter 与 SimpleDateFormat 对比
其实在之前的 Java API 中,日期时间格式化类 SimpleDateFormat
是最常用的工具之一,也是非常让人困惑和提心吊胆的一个,因为经常会听到前辈讲,这个 API 是非线程安全的。
Java8 提供了新的日期时间 API,其中包括用于日期时间格式化的 DateTimeFormatter
,它与 SimpleDateFormat
有什么区别呢?
两者最大的区别是,Java8 的 DateTimeFormatter 是线程安全的,而 SimpleDateFormat 并不是线程安全的。
这是不是就意味着,我们在新版本的 JDK 中,要尽量使用线程安全的时间格式化 API DateTimeFormatter
呢?
首先看一下老版本的格式化类是怎么做线程安全处理的。
并发环境下的 SimpleDateFormat
一般来说,为了能够在多线程环境下正确的使用 SimpleDateFormat
,最常用的处理方法有这三种:
方法一:局部变量
在需要执行格式化的地方都新建 SimpleDateFormat 实例,使用局部变量来存放 SimpleDateFormat 实例。
public static String formatDate(Date date)throws ParseException{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
这种方法的缺点是可能会导致短期内创建大量的 SimpleDateFormat 实例,如解析一个 excel 表格里的字符串日期。
方法二:静态成员变量
为了避免创建大量的 SimpleDateFormat 实例,往往会考虑把 SimpleDateFormat 实例设为静态成员变量,共享 SimpleDateFormat 对象。
这种情况下就要对 SimpleDateFormat 添加同步。
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatDate(Date date)throws ParseException{
synchronized(sdf){
return sdf.format(date);
}
}
这种方法的缺点也很明显,就是在高并发的环境下会导致解析被阻塞。
方法三:ThreadLocal(推荐)
要在高并发环境下能有比较好的体验,可以使用 ThreadLocal 来限制 SimpleDateFormat 只能在线程内共享,这样就避免了多线程导致的线程安全问题。
private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
}
public static String format(Date date) {
return threadLocal.get().format(date);
}
这样就可以保证线程安全性和效率兼顾。
DateTimeFormatter
因为 DateTimeFormatter 类是天然的线程安全,所以可以直接使用,不需要担心线程并发问题。
解析日期:
String dateStr= "2018年08月13日";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
LocalDate date= LocalDate.parse(dateStr, formatter);
日期转换为字符串:
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm a");
String nowStr = now .format(format);
由 DateTimeFormatter 的静态方法 ofPattern()
构建日期格式,LocalDateTime 和 LocalDate 等一些表示日期或时间的类使用 parse
和 format
方法把日期和字符串做转换。
使用新的 API,整个转换过程都不需要考虑线程安全的问题。
总结
总的来说,新版的 API 简单易用,并且是线程安全的,所以如果用的是 JDK 8 以上的版本,还是首要考虑使用 DateTimeFormatter
。
至于其他的一些时间 API 使用习惯,也需要改过来,下面会写一篇关于如何互相转换 LocalDateTime
和 Date
类,这也是阻碍使用 DateTimeFormatter
的一大障碍。