2020 年,你還在使用 Java 中的 SimpleDateFormat 嗎?

2020-12-11 CSDN

作者 | 阿文

責編 | 屠敏

今天我和大家一起聊一聊SimpleDateFormat ,這都2020年了,怎麼還在用SimpleDateFormat ?

其實,作為一名Java 程式設計師,我們會經常在編程時候和時間打交道,比如要把某一個時間存儲到資料庫中去,而我們直接使用

Datedate = newDate(); System.out.println(date);

得到的時間都是這樣的

SunJun 07 17:22:52CST 2020

因此,我們經常需要把時間進行格式化處理,然後在進行存儲,方便閱讀。這個時候我們就會使用到SimpleDateFormat 類,比如使用下面的代碼來獲取當前時間,並調用SimpleDateFormat 對時間進行格式化:

Date date = newDate(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設置日期格式String datestr = df.format(date); System.out.println(datestr);

最終輸出的時間為

2020-06-07 16:45:58

由於在java 8之前 SimpleDateFormat 是一個比較常用的類,但是我還是在這裡要建議開發者不要用 SimpleDateForma。原因有兩點:

首先,通過new 一個對象來操作對象,佔用內存大,如果每處理一個時間信息的時候,就需要new一個SimpleDateFormat實例對象,然後再丟棄這個對象。大量的對象就這樣被創建出來,佔用大量的內存和 jvm空間。

那麼很多人就會想,既然new 代價太大, 不如我們使用 static 將其設置為共享變量,這樣就可以減小頻繁創建對象帶來的內存開銷啦,真的是機智如我。

privatestatic SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

但是這樣操作在並發量非常大的情況下,由於 SimpleDateFormat 是線程不安全的,這也是第二點原因,這個在JDK文檔中已經明確表明了SimpleDateFormat不應該用在多線程場景中:

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

在《阿里巴巴 Java 開發手冊》中也明確表示不要定義SimpleDateFormat 為static 變量,如果定義static 必須要加鎖。

這背後的原因是由於 SimpleDateFormat 中的format方法在執行過程中,會使用一個成員變量calendar來保存時間。

private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) {this.calendar.setTime(date); boolean useDateFormatSymbols = this.useDateFormatSymbols();int i = 0; ……

由於在聲明SimpleDateFormat的時候,使用的是static定義的。那麼這個SimpleDateFormat就是一個共享變量,SimpleDateFormat 中的calendar也就可以被多個線程訪問到。

舉個例子:假設一個線程A剛執行完calendar.setTime把時間設置成2020-05-07,這個線程還沒執行完,線程B又執行了calendar.setTime把時間改成了2020-06-07。這時候線程A繼續往下執行,拿到的calendar.getTime得到的時間就是線程B改過之後的。

除了format方法以外,SimpleDateFormat的parse方法也有同樣的問題。

所以,不要把SimpleDateFormat作為一個共享變量使用。

那麼如何解決這樣的問題呢?如果你使用的是Java 8 之前的JDK,那麼上面的《阿里巴巴Java 開發手冊》已經給出了解決方案,那就是使SimpleDateFormat 變成線程安全的,通過加鎖的方式來解決

privatestatic ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {@Overrideprotected DateFormat initialValue(){returnnew SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } };

而如果你使用的是Java 8 + 的版本,那麼你完全可以拋棄這種線程不安全的時間格式化方法。可以使用DateTimeFormatter代替SimpleDateFormat,這是一個線程安全的格式化工具類。

LocalDate 和LocalDateTime

Java 8開始,明確了日期時間概念,例如:瞬時(instant)、 長短(duration)、日期、時間、時區和周期。

同時繼承了Joda 庫按人類語言和計算機各自解析的時間處理方式。不同於老版本,新API基於ISO標準日曆系統,java.time包下的所有類都是不可變類型而且線程安全。

關鍵類

Instant:瞬時實例。LocalDate:本地日期,不包含具體時間 例如:2014-01-14 可以用來記錄生日、紀念日、加盟日等。LocalTime:本地時間,不包含日期。LocalDateTime:組合了日期和時間,但不包含時差和時區信息。ZonedDateTime:最完整的日期時間,包含時區和相對UTC或格林威治的時差。新API還引入了 ZoneOffSet 和 ZoneId 類,使得解決時區問題更為簡便。解析、格式化時間的 DateTimeFormatter 類也全部重新設計。

例如,我們使用LocalDate 代替Date,使用DateTimeFormatter 代替SimpleDateFormat,如下所示:

String DateNow = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")); // 當前日期和時間 System.out.println(DateNow);

這樣就避免了SimpleDateFormat 的線程不安全問題啦。

相關焦點

  • 為什麼SimpleDateFormat不是線程安全的?
    👨‍💻面試官:項目中的日期轉換怎麼用的?SimpleDateFormat 用過嗎?能說一下 SimpleDateFormat 線程安全問題嗎,以及如何解決? {            Date date = simpleDateFormat.parse(dateString);            String newDate = simpleDateFormat.format(date).toString();            if(!
  • java中使用 SimpleDateFormat 格式化日期
    Hi,大家好久不見,今天我們在這裡給大家介紹一下關於Java的小知識,在Java中我們應該如何使用 SimpleDateFormat 格式化日期並顯示,至於運用呢就不和大家做詳細介紹了;接下來就給大家詳細介紹一下如何實現。那我們該如何創建使用呢?
  • SimpleDateFormat 如何安全的使用?
    但是,建議使用 DateFormat 中的 getTimeInstance、 getDateInstance 或 getDateTimeInstance 方法來創建一個日期-時間格式。 這幾個方法會返回一個默認的日期/時間格式。 你可以根據需要用 applyPattern 方法修改格式方式。日期時間格式日期和時間格式由 日期和時間模式字符串 指定。
  • 不簡單的 Java SimpleDateFormat
    在 Java 中格式化和解析日期的一種常見方法是使用 SimpleDateFormat。下面是我們用到的一個公共類。(Date target) { return SIMPLE_DATE_FORMAT.format(target); }}你覺得它會像我們預期的那樣進行工作麼?
  • 聽說你還在用SimpleDateFormat格式化日期
    = new SimpleDateFormat("yyyy-MM-dd");Date stationTime = dateFormat.parse(dateFormat.format(svcWorkOrderPo.getPayEndTime()));orderDailyStatisticsPo.setStatisticalDate(stationTime);而且項目中的時間和日期API用的也比較混亂
  • 不簡單的 SimpleDateFormat
    在 Java 中格式化和解析日期的一種常見方法是使用 SimpleDateFormat。下面是我們用到的一個公共類。(Date target) { return SIMPLE_DATE_FORMAT.format(target); }}你覺得它會像我們預期的那樣進行工作麼?
  • java中date日期計算使用方法
    在java中,日期時間類是我們經常使用的一個類。那麼怎麼創建時間類呢。很簡單,代碼如下:Date date = new Date();上述代碼便初始化了一個時間類,雖然簡單,但是裡面的坑不少。單純的這樣寫並不能輸出我們想要的數據。上面代碼將會輸出一個標準國際時間,如圖所示:
  • 【107期】SimpleDateFormat 的線程安全問題與解決方案
    2020年百日百更原創Java最全面試題庫之往期回顧1.原因 SimpleDateFormat(下面簡稱sdf)類內部有一個Calendar對象引用,它用來儲存和這個sdf相關的日期信息,例如sdf.parse(dateStr), sdf.format(date) 諸如此類的方法參數傳入的日期相關String, Date等等, 都是交友Calendar引用來儲存的.
  • 為什麼阿里巴巴禁止把SimpleDateFormat定義為static類型的?
    在Java中,可以使用SimpleDateFormat的format方法,將一個Date類型轉化成String類型,並且可以指定輸出格式。如果你想要轉換成其他格式,只要指定不同的時間模式就行了。在Java中,可以使用SimpleDateFormat的parse方法,將一個String類型轉化成Date類型。
  • java中定義日期格式的轉換符
    =String.format(Locale.US,"英文月份簡稱:%tb",date);System.out.println(str);System.out.printf("本地月份簡稱:%tb%n",date);//B的使用,月份全稱str
  • 面試官一步一步的套路你,為什麼SimpleDateFormat不是線程安全的
    面試官:SimpleDateFormat用過嗎?
  • 俠說java8-LocalDateTime等時間使用手冊(全),先mark後看
    : Fri Jan 17 16:52:59 CST 2020 Date date = new Date(); System.out.println("date : " + date); //1. instant : 2020-01-17T08:52:59.235Z Instant instant = date.toInstant();
  • JAVA日期Date轉換String其實很簡單
    JAVA提供了一個在Date類型和String類型之間互換的類:java.text.SimpleDateFormat,我們先來看下這個類的構造函數= new Date(); String pattern = "yyyy年MM月dd日 HH時mm分ss秒"; String pattern2 = "yyyy-MM-dd HH:mm:ss"; String pattern3 = "一年中的第 D 天 一年中第w個星期 一月中第W
  • java.util.Date 與 java.sql.Date 相關知識點解析
    問:java.sql.Date 和 java.util.Date 有什麼區別?
  • Jmeter使用之:怎麼編寫擴展函數(一)
    1、首先編寫我們的java類,如具體代碼如下:package com.ste.ruink.timetool;import java.text.SimpleDateFormat;import java.util.Date;public class TimeConvert {/** 獲取時間,當前時間往前(
  • 【問答】MySQL DATE_FORMAT函數怎麼用?
    問: 在MySQL中如何使用DATE_FORMAT(
  • java日期和時間的格式化
    「XXXX年XX月XX日」的格式。format("當前日期為:%tY年%tm月%td日", date,date,date);System.使用String類format()方法格式化日期,任務要求日期格式化為「XXXX年XX月XX日」,在format()方法的格式化串中使用了%tY、%tm、%td格式化符,%tY獲取Date對象的4位年份(如2019),%tm獲取Date對象的2位月份(如06),%td獲取Date對象的2位天數(如12),format()方法的args參數使用date變量。
  • 18 個示例帶你掌握 Java 8 日期時間處理!
    和java.util.Date不同,它只有日期,不包含時間。當你僅需要表示日期時就用這個類。我們通過靜態工廠方法now()非常容易地創建了當天日期,你還可以調用另一個有用的工廠方法LocalDate.of()創建任意日期, 該方法需要傳入年、月、日做參數,返回對應的LocalDate實例。
  • Java 8時間類,越用越香
    而java8中日期和時間基本都被設計final,final修飾的類,天然線程安全。設計很差java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期,兩個類又有相同的名字,令人匪夷所思。
  • Java基礎教程:Java之Object類,Objects類,Date類概念及使用!
    Object類概述java.lang.Object類是Java語言中的根類,即所有類的父類。它中描述的所有方法子類都可以使用。在對象實例化的時候,最終找的父類就是Object。如果一個類沒有特別指定父類, 那麼默認則繼承自Object類。