偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Java.util.Date 已死!請(qǐng)不要再使用

開發(fā) 前端
在本文中,我將先為你剖析為何不推薦使用Date類,接著通過實(shí)際的代碼示例,為你展示一些現(xiàn)代的解決方案。

環(huán)境:SpringBoot3.4.2

1. 簡(jiǎn)介

在Java8之前,處理時(shí)間使用java.util.Date是最主流,最廣泛的方式。如下示例:

// 1. 獲取當(dāng)前時(shí)間
Date now = new Date();
System.out.println("當(dāng)前時(shí)間: " + now);
// 2. 創(chuàng)建特定時(shí)間(已廢棄的構(gòu)造方法,但仍有使用)
@SuppressWarnings("deprecation")
Date specificDate = new Date(2025 - 1900, 11, 25); // 年份從1900開始計(jì)算,月份0-11
System.out.println("特定日期: " + specificDate); // 輸出可能不符合預(yù)期(時(shí)區(qū)問題)
// 3. 比較日期(使用 before()/after())
Date earlier = new Date(System.currentTimeMillis() - 1000);
System.out.println("now 是否在 earlier 之后? " + now.after(earlier));

輸出結(jié)果

當(dāng)前時(shí)間: Mon Aug 18 07:37:08 CST 2025
特定日期: Thu Dec 25 00:00:00 CST 2025
now 是否在 earlier 之后? true

問題:

  • Date 的構(gòu)造方法 Date(int year, int month, int day) 已廢棄(年份需 -1900,月份 0-11)
  • 輸出格式不友好(如 Mon Dec 25 00:00:00 CST 2023),需配合 SimpleDateFormat 格式化

示例2:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 1. 格式化 Date 為字符串
Date now = new Date();
String formattedDate = sdf.format(now);
System.out.println("格式化后: " + formattedDate);
// 2. 解析字符串為 Date
String dateStr = "2025-11-25 12:00:00";
Date parsedDate = sdf.parse(dateStr);
System.out.println("解析后: " + parsedDate);

輸出結(jié)果

格式化后: 2025-08-17 07:38:10
解析后: Tue Nov 25 12:00:00 CST 2025

問題:

  • SimpleDateFormat 不是線程安全的(多線程環(huán)境下需額外處理)
  • 時(shí)區(qū)處理復(fù)雜(需手動(dòng)設(shè)置 setTimeZone())

但多年過去,我漸漸認(rèn)識(shí)到——有時(shí)還是吃了苦頭才明白——這個(gè)類在設(shè)計(jì)上存在諸多陷阱,會(huì)讓你的代碼變得脆弱且難以理解。

好在,Java也在不斷進(jìn)化。

如今,我們有了更優(yōu)秀、更安全、更簡(jiǎn)潔,用起來也更加得心應(yīng)手的替代方案。

在本文中,我將先為你剖析為何不推薦使用Date類,接著通過實(shí)際的代碼示例,為你展示一些現(xiàn)代的解決方案。

2. 為什么避免使用Date

2.1 名稱具有誤導(dǎo)性

盡管名為“Date”(日期),但它并不只是表示一個(gè)日期(如 2025 年 8 月 17 日)。

相反,它表示的是一個(gè)時(shí)間戳——即自 1970 年 1 月 1 日(紀(jì)元)起以毫秒為單位計(jì)量的某個(gè)特定時(shí)刻。如下示例:

Date now = new Date();
System.out.println("當(dāng)前時(shí)間: " + now);
// 輸出結(jié)果:當(dāng)前時(shí)間: Mon Aug 17 07:43:41 CST 2025

可讀性差,格式不直觀;底層以毫秒數(shù)存時(shí)間戳,它只是一個(gè)長(zhǎng)值(date.getTime()),而不是 "日歷日期"。

替代方案:

如果你要的是不帶時(shí)間的日歷日期,請(qǐng)使用 LocalDate。

LocalDate today = LocalDate.now();
System.out.println(today);

輸出結(jié)果

2025-08-17

干凈、清晰,沒有混淆。

2.2 可變性問題

Date 對(duì)象是可變的。

你可以更改其內(nèi)部值,這使得它們?cè)诠蚕頃r(shí)存在安全隱患,并迫使采用防御性復(fù)制。

Date date = new Date() ;
date.setTime(0L) ; 
System.err.println(date) ;

輸出結(jié)果

Thu Jan 01 08:00:00 CST 1970

是不是驚呆了,輸出1970。

如果其他代碼引用了你的 Date 對(duì)象,它就會(huì)背著你把它弄亂。

這就是產(chǎn)生 bug 的原因。

替代方案:

java.time 包中的所有類都是不可變和線程安全的。

LocalDateTime now = LocalDateTime.now() ;
LocalDateTime changed = now.plusDays(5) ;
System.out.println(now) ;
System.out.println(changed) ;

輸出結(jié)果

2025-08-17T07:54:25.775775700
2025-08-22T07:54:25.775775700

請(qǐng)注意,plusDays(5) 并沒有修改原始的 now,而是返回一個(gè)新的實(shí)例。

2.3 糟糕的 API 設(shè)計(jì)

如果你用過 getYear()、getMonth() 或 getDay() 等方法,你就會(huì)知道 Date 是多么痛苦:

Date date = new Date(); 
// 返回的是自1900年以來的年數(shù)(125)
System.out.println(date.getYear()); 
// 月份從0開始計(jì)數(shù)(0代表一月)(7)
System.out.println(date.getMonth()); 
// 返回星期幾(0代表星期日)
System.out.println(date.getDay());

并且上面3個(gè)方法都已經(jīng)標(biāo)記為廢棄。

替代方案:

使用具有簡(jiǎn)潔流暢 API 的 LocalDateTime 或 ZonedDateTime。

LocalDateTime now = LocalDateTime.now();
System.out.println(now.getYear());
System.out.println(now.getMonth());
System.out.println(now.getDayOfWeek());

輸出結(jié)果

2025
AUGUST
MONDAY

2.4 時(shí)區(qū)模糊

Date#toString() 使用系統(tǒng)默認(rèn)時(shí)區(qū)。

這意味著同一個(gè) Date 對(duì)象在不同的機(jī)器上可能顯示不同的時(shí)區(qū)。

圖片圖片

想象一下,你在調(diào)試一個(gè)生產(chǎn)環(huán)境中的故障:不同地區(qū)的服務(wù)器對(duì)同一時(shí)刻記錄的時(shí)間卻各不相同。

替代方案:

使用 java8 Instant 表示機(jī)器時(shí)間,或使用 ZonedDateTime 表示人類友好時(shí)間。

Instant instant = Instant.ofEpochMilli(0);
System.out.println(instant); 
// 帶時(shí)區(qū)的可讀格式
ZonedDateTime zoned = instant.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zoned);

輸出結(jié)果

1970-01-01T00:00:00Z
1970-01-01T08:00+08:00[Asia/Shanghai]

2.5 子類化的怪異現(xiàn)象

你是否遇到過 java.sql.Date 或 java.sql.Timestamp?

這些 java.util.Date 的子類對(duì)方法的重寫方式可能會(huì)讓你大吃一驚。

這是典型的反面教材,展示了繼承為何可能帶來風(fēng)險(xiǎn)。

替代方案:

JDBC 現(xiàn)在可直接使用 java.time 類,如 LocalDate、LocalTime、Instant 等。無需使用古怪的子類。

Connection conn = null ;
PreparedStatement ps = conn.prepareStatement("INSERT INTO users (dob) VALUES (?)");
ps.setObject(1, LocalDate.of(1993, 5, 15));
ps.executeUpdate();

這種方式更清晰,且能避免意外的類型不匹配問題。

3. 現(xiàn)代替換方案

那么,除了 java.util.Date,你應(yīng)該使用什么呢?讓我們逐一分析常見場(chǎng)景:

3.1 當(dāng)你需要當(dāng)前時(shí)刻(機(jī)器時(shí)間)時(shí)

舊方式

Date now = new Date() ;

新方式

Instant now = Instant.now() ;

Instant 非常使用表示時(shí)間戳,精確,不可變且使用使用UTC時(shí)區(qū)。

3.2 當(dāng)你需要一個(gè)不帶時(shí)間的日期日期時(shí)

舊方式:你最終還是會(huì)得到一個(gè)完整的Date對(duì)象,然后手動(dòng)去除時(shí)間部分。

新方式

LocalDate today = LocalDate.nwo() ;
System.out.println(today) ; // 2025-08-17

LocalDate 值提供日期。

3.3 當(dāng)你需要一個(gè)不帶日期的時(shí)間點(diǎn)時(shí)

Date無法很好地表示這種情況。

新方式:

LocalTime now = LocalTime.now() ;
System.out.println(now) ; // 08:30:22.146

非常適合表示 那種具體時(shí)間點(diǎn)的場(chǎng)景。

3.4 當(dāng)你需要日期和時(shí)間,但不需要時(shí)區(qū)時(shí)

舊方式:Date會(huì)提供一個(gè)時(shí)間戳,但其表示形式取決于系統(tǒng)的默認(rèn)設(shè)置。

新方式:

LocalDateTime meeting = LocalDateTime.of(2025, 8, 19, 14, 30) ;
System.out.println(meeting) ; // 2025-08-19T14:30

LocalDateTime明確且易于閱讀。

3.5 當(dāng)你需要日期,時(shí)間和時(shí)區(qū)時(shí)

舊方式:使用 Date + Calendar 極其繁瑣。

// 1. 創(chuàng)建 Calendar 實(shí)例(需指定時(shí)區(qū))
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"));
// 2. 設(shè)置日期和時(shí)間(手動(dòng)拆分年/月/日等)
calendar.set(2025, Calendar.AUGUST, 17, 14, 30, 0); // 注意:月份從0開始(8月=7)
calendar.set(Calendar.MILLISECOND, 0); // 清除毫秒(可選)
// 3. 獲取 Date 對(duì)象(僅時(shí)間戳,無時(shí)區(qū)信息)
Date oldDate = calendar.getTime();
// 4. 輸出時(shí)需手動(dòng)格式化(且無法直接顯示時(shí)區(qū))
System.out.println("舊方式結(jié)果: " + oldDate); 
// 5. 若需時(shí)區(qū)信息,需額外處理...
TimeZone timeZone = calendar.getTimeZone();
System.out.println("時(shí)區(qū): " + timeZone.getDisplayName()); // 輸出:中國(guó)標(biāo)準(zhǔn)時(shí)間

輸出結(jié)果

舊方式結(jié)果: Sun Aug 17 14:30:00 CST 2025
時(shí)區(qū): 中國(guó)標(biāo)準(zhǔn)時(shí)間

新方式:

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("UTC+8")) ;
// 2025-08-17T08:32:13.666470100+08:00[UTC+08:00]
System.out.println(zdt) ;

ZonedDateTime 使時(shí)區(qū)處理變得明確,避免了隱藏的問題。

3.6 當(dāng)你需要時(shí)間段或周期時(shí)

舊方式:你需要手動(dòng)計(jì)算兩個(gè) Date 之間的毫秒數(shù)。

新方式:

LocalDate start = LocalDate.of(2025, 1, 1) ;
LocalDate end = LocalDate.of(2025, 8, 17) ;
Period period = Period.between(start, end) ;
System.out.println(period) ;

輸出結(jié)果

P7M16D (7個(gè)月16天)

計(jì)算精確的時(shí)間差:

Instant start = Instant.now() ;
TimeUnit.MILLISECONDS.sleep(3000) ;
Instant end = Instant.now() ;
Duration duration = Duration.between(start, end) ;
System.err.println(duration + " ms") ;

輸出結(jié)果

PT3.0138012S ms

3.7 從Date遷移到j(luò)ava.time 

你經(jīng)常會(huì)遇到仍在使用 Date 的遺留API。

轉(zhuǎn)換很容易:

// Date -> Instant
Date d = new Date();
Instant instant = d.toInstant() ;
// Instant -> Date
Date dd = Date.from(instant) ;


責(zé)任編輯:武曉燕 來源: Springboot全家桶實(shí)戰(zhàn)案例
相關(guān)推薦

2024-08-19 08:16:57

@Resource@AutowiredSpring

2025-08-18 09:35:02

2023-02-06 07:37:29

Java編程語(yǔ)言

2012-02-20 10:12:09

Java

2010-01-12 09:43:15

Java已死

2014-12-05 10:06:44

程序員

2024-09-03 09:31:59

2011-05-11 09:01:29

面向?qū)ο蠹夹g(shù)函數(shù)式語(yǔ)言

2025-04-08 08:25:00

前端埋點(diǎn)線程

2011-01-07 10:18:28

RSSWeb

2022-09-15 10:44:42

SidecarIstioeBPFizer

2015-04-22 15:02:33

公共PaaSIT運(yùn)維Docker

2021-05-15 08:35:22

數(shù)據(jù)庫(kù)CAP模式

2014-01-06 09:36:53

IT部門BYODBYOA

2009-09-12 10:59:37

2025-07-28 02:22:00

2020-10-12 10:45:44

nullava程序員

2015-08-31 10:59:22

2011-12-07 10:20:19

Email新聞

2021-01-19 10:58:15

漏洞管理漏洞數(shù)據(jù)泄露
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)