JAVA8为啥要用DateTimeFormatter代替SimpleDateFormat?

阿里java规范

阿里java规范第六节第5点提到SimpleDateFormat 是线程不安全的类,使用时需注意

Java 8 引入的 DateTimeFormatter 类替代了旧有的 SimpleDateFormat 类

两者的区别考虑和优势

线程安全性

  • SimpleDateFormat:不是线程安全的。如果多个线程同时访问同一个SimpleDateFormat实例进行日期和字符串的转换,可能会导致数据不一致或抛出异常。为了在多线程环境下安全使用,通常需要使用ThreadLocal为每个线程提供独立的SimpleDateFormat实例,或者通过其他同步机制来保证线程安全。

  • DateTimeFormatter:是线程安全的。它可以在多线程环境中被共享和重用,无需担心线程安全问题。DateTimeFormatter的不可变性(immutability)和内部设计使其在多线程环境下能够保持数据的完整性和一致性。

安全性是最大的区别,安全性区别主要体现在多线程情况下,下面通过代码示例验证安全性方面的区别:

DateTimeFormatter多线程下安全性代码演示

public static void main(String[] args) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 格式化日期时间
                    LocalDateTime now = LocalDateTime.now();
                    String formattedDateTime = dateTimeFormatter.format(now);
                    System.out.println("格式化后的日期时间:" + formattedDateTime);

                    // 解析日期时间
                    String dateTimeString = "2023-07-03 12:30:45";
                    LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString, dateTimeFormatter);
                    System.out.println("解析后的日期时间:" + parsedDateTime);
                }
            }).start();
        }
    }

通过创建3个线程分别进行格式化时间和解析日期的操作,使用DateTimeFormatter能够安全的进行相关操作,没有什么问题

格式化后的日期时间:2024-08-03 08:48:06
格式化后的日期时间:2024-08-03 08:48:06
格式化后的日期时间:2024-08-03 08:48:06
解析后的日期时间:2023-07-03T12:30:45
解析后的日期时间:2023-07-03T12:30:45
解析后的日期时间:2023-07-03T12:30:45

SimpleDateFormat多线程下安全性代码演示

public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 格式化日期时间
                    Date now = new Date();
                    String formattedDateTime = sdf.format(now);
                    System.out.println("格式化后的日期时间:" + formattedDateTime);

                    // 解析日期时间
                    String dateTimeString = "2023-07-03 12:30:45";
                    try {
                        Date parsedDateTime = sdf.parse(dateTimeString);
                        System.out.println("解析后的日期时间:" + parsedDateTime);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

同样的创建3个线程,进行相同的格式化时间和解析日期的操作,使用SimpleDateFormat则会抛出异常

格式化后的日期时间:2024-08-03 08:50:11
格式化后的日期时间:2024-08-03 08:50:11
格式化后的日期时间:2024-08-03 08:50:11
解析后的日期时间:Sat Jul 03 12:30:45 CST 2202
解析后的日期时间:Thu Jul 01 21:30:45 CST 2202
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: ""
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.base/java.lang.Long.parseLong(Long.java:702)
	at java.base/java.lang.Long.parseLong(Long.java:817)
	at java.base/java.text.DigitList.getLong(DigitList.java:195)
	at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121)
	at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
	at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
	at java.base/java.text.DateFormat.parse(DateFormat.java:393)
	at org.example.randomTest$2.run(randomTest.java:81)
	at java.base/java.lang.Thread.run(Thread.java:834)

DateTimeFormatter多线程安全原因

由此可见DateTimeFormatter是线程安全性,究其原因主要是DateTimeFormatter源码中入参是final 修饰的,不可变变量是线程安全的

SimpleDateFormat多线程下如果保证安全性?

当然如果多线程中一定要使用SimpleDateFormat也不是不行,只需要使用ThreadLocal为每个线程提供独立的SimpleDateFormat实例,或者通过其他同步机制来保证线程安全。

SimpleDateFormat保证多线程安全代码演示

public class DateFormatTest {
    private static final ThreadLocal<SimpleDateFormat> sdf = 
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

    public static void main(String[] args) {
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 格式化日期时间
                    Date now = new Date();
                    String formattedDateTime = sdf.get().format(now);
                    System.out.println("格式化后的日期时间:" + formattedDateTime);

                    // 解析日期时间
                    String dateTimeString = "2023-07-03 12:30:45";
                    try {
                        Date parsedDateTime = sdf.get().parse(dateTimeString);
                        System.out.println("解析后的日期时间:" + parsedDateTime);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

这样的话,多线程就没啥问题了

格式化后的日期时间:2024-08-03 09:05:50
格式化后的日期时间:2024-08-03 09:05:50
格式化后的日期时间:2024-08-03 09:05:50
格式化后的日期时间:2024-08-03 09:05:50
格式化后的日期时间:2024-08-03 09:05:50
解析后的日期时间:Mon Jul 03 12:30:45 CST 2023
解析后的日期时间:Mon Jul 03 12:30:45 CST 2023
解析后的日期时间:Mon Jul 03 12:30:45 CST 2023
解析后的日期时间:Mon Jul 03 12:30:45 CST 2023
解析后的日期时间:Mon Jul 03 12:30:45 CST 2023

设计哲学

SimpleDateFormat 的设计受到 Java 早期版本的限制,其 API 并不完全符合 Java 的新特性和设计哲学。SimpleDateFormat 的扩展性和灵活性较差,难以支持新的日期时间格式。
DateTimeFormatter 是 Java 8 日期时间 API(JSR-310)的一部分,这个新的 API 设计得更加模块化、易于理解和使用。DateTimeFormatter 提供了丰富的功能,包括解析和格式化日期时间,以及自定义模式字符串等。

国际化

SimpleDateFormat 在处理国际化时存在一些问题,特别是与区域设置(Locale)相关的日期时间格式。它可能无法完全满足各种语言和文化的需求。
DateTimeFormatter 提供了更好的国际化支持,能够根据区域设置自动选择适当的日期时间格式。同时,它也支持自定义模式字符串,允许开发者根据需要进行灵活的配置。

性能

尽管性能不是替换 SimpleDateFormat 的主要原因,但 DateTimeFormatter 在某些情况下可能表现出更好的性能。这主要是因为 DateTimeFormatter 是不可变的,可以在编译时进行优化,并且避免了线程同步的开销。

易用性和清晰度

DateTimeFormatter 的 API 设计得更加清晰和易用,提供了更多的方法和选项来配置和定制日期时间的格式。这使得开发者能够更容易地理解和使用它,同时也减少了出错的可能性。

总结

综上所述,Java 8 引入 DateTimeFormatter 替代 SimpleDateFormat 是出于多种考虑和优势,包括线程安全性、设计哲学、国际化支持、性能以及易用性和清晰度等方面。这些改进使得 Java 的日期时间处理更加现代、灵活和强大。因此,在Java 8及以后版本中,推荐使DateTimeFormatter来代替SimpleDateFormat进行日期时间的格式化和解析。

  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值