常用的 API
1. 正則表達式
(1) 題目:貪婪爬取和非貪婪爬取
① 貪婪爬取:爬取數據的時候盡可能的多獲取數據
② 非貪婪爬取:爬取數據的時候盡可能的少獲取數據
③ Java中默認的是貪婪爬取
④ + 后面加上 ? 可以轉變為非貪婪爬取
(2) 捕獲分組
捕獲分組通過 (...)
將部分正則表達式包裹,會保存該組的匹配結果;后續可通過 \\n
(n
為分組編號,從1
開始)反向引用這組結果,實現 “重復使用已匹配的內容”。
需求 1:單字符首尾一致(如?a123a
、b456b
)
正則表達式:(. ).+\\1
① 邏輯分解:
(. )
:第1
個捕獲組,匹配任意一個字符(.
匹配任意字符,括號捕獲該字符)。.+
:匹配中間任意長度的字符(1個或多個)。\\1
:反向引用第1
個捕獲組的內容,要求結尾字符必須和開頭捕獲的單個字符一致。
②?示例驗證:
a123a
?→ 開頭捕獲a
,結尾a
?→ 匹配成功。a123b
?→ 開頭a
,結尾b
?→ 匹配失敗。
需求 2:多字符首尾一致(如?abc123abc
、&|@abc&|@
)
正則表達式:(.+).+\\1
① 邏輯分解:
(.+)
:第1
個捕獲組,+
表示 “1
個或多個字符”,即匹配任意長度的開頭子串(至少1
個字符)。.+
:匹配中間任意長度字符。\\1
:反向引用第1
個捕獲組的內容,要求結尾子串必須和開頭捕獲的多字符子串完全一致。
② 示例驗證:
abc123abc
?→ 開頭捕獲abc
,結尾abc
?→ 匹配成功。abc123abd
?→ 開頭abc
,結尾abd
?→ 匹配失敗。
需求 3 :首尾多字符(內部字符一致),且中間至少有 1 個字符,且開頭內部至少重復 1 次
正則表達式:((.)\\2+).+\\1
① 最內層:(.)
(第 2 個捕獲組)
(.)
:(
?表示創建捕獲組,.
?匹配任意單個字符(比如?a
、b
、&
?等)。- 這部分的作用:捕獲一個 “基礎字符”,后續會重復使用這個字符。
- 編號:因為是第 2 個出現的左括號(第一個左括號是外層的?
(
),所以是第 2 組,后續用?\\2
?引用。
② 中間層:\\2+
\\2
:反向引用第 2 組捕獲的 “基礎字符”(比如第 2 組捕獲了?a
,\\2
?就代表?a
)。+
:量詞,表示 “至少出現 1 次”(和?*
?不同,*
?允許 0 次,+
?必須 1 次及以上)。- 組合起來:
\\2+
?表示 “基礎字符至少重復 1 次”(比如基礎字符是?a
,就匹配?aa
、aaa
、aaaa
?等)。
③ 外層分組:((.)\\2+)
(第 1 個捕獲組)
- 把?
(.)
?和?\\2+
?整體包裹,形成第 1 組。 - 作用:捕獲 “由同一個基礎字符重復組成的子串”,且這個子串長度至少 2 個字符(因為基礎字符 1 個 + 至少重復 1 次 = 2 個及以上)。
例如:- 基礎字符?
a
?+?\\2+
(a
?重復 2 次)→ 第 1 組捕獲?aaa
; - 基礎字符?
&
?+?\\2+
(&
?重復 1 次)→ 第 1 組捕獲?&&
。
- 基礎字符?
④ 中間內容:.+
.
?匹配任意字符,+
?表示 “至少 1 次”。- 作用:要求開頭和結尾的子串之間,必須有至少 1 個字符(不能是空的)。
⑤ 結尾:\\1
- 反向引用第 1 組捕獲的內容(即 “由同一個基礎字符重復組成的子串”)。
- 作用:要求字符串結尾的子串,必須和開頭的子串完全一致。
需求 4:“口吃” 字符去重
將包含重復字符的字符串(如?我要學學編編編編編程程程程程程
),替換為單個重復字符,最終得到?我要學編編程
。
public class RegexDemo4 {public static void main(String[] args) {// 原始字符串:包含重復的“學”“編”“程”String str = "我要學學編編編編編程程程程程程";// 正則:匹配“單個字符 + 至少1個相同重復字符”String regex = "(.)\\1+";// 替換:用“基準字符($1)”替換“重復字符組”String result = str.replaceAll(regex, "$1");System.out.println(result); // 輸出:我要學編編程}
}
關鍵邏輯 1:拆解?(.)\\1+
① 處理?“學學”
:
(.)
?捕獲第一個?“學”
(組 1 存?“學”
);\\1+
?匹配第二個?“學”
(滿足 “至少 1 次”);- 匹配到?
“學學”
,替換成?“$1”
(即?“學”
)。
② 處理?“編編編”
:
(.)
?捕獲第一個?“編”
(組 1 存?“編”
);\\1+
?匹配后面的?“編編”
(至少 1 次);- 匹配到?
“編編編”
,替換成?“編”
。
③ 處理?“程”
:
- 因為?
“程”
?沒有重復(\\1+
?要求至少 1 次重復,不滿足),所以不匹配正則,保留原樣。
④ 最終結果就是?“學編程”
。
關鍵邏輯 2:$1 的作用
① $1
?是正則表達式替換操作中的反向引用語法,用于在「替換字符串」中,引用正則里第一個捕獲組(由圓括號?()
?包裹的部分)所匹配到的具體內容。
② 核心作用:在字符串替換時,用「捕獲組匹配到的內容」替換「整個正則匹配到的重復 / 復雜內容」,實現 “提取關鍵部分,簡化重復內容”?的效果。
③ 舉例理解:
比如要把字符串?"aaaabbbcc"
?中連續重復的字符壓縮成單個:
(1) 正則表達式:(.)\\1+
(.)
?是第一個捕獲組,負責 “捕獲單個任意字符”(比如匹配?"aaaa"
?時,捕獲組會抓到?'a'
);\\1+
?表示 “必須跟著至少一個和捕獲組內容相同的字符”(即重復的?'a'
)。
(2) 替換字符串:"$1"
當正則匹配到?"aaaa"
?時,$1
?會引用第一個捕獲組抓到的?'a'
,于是用?'a'
?替換整個?"aaaa"
;同理,"bbb"
?會被?'b'
?替換,"cc"
?會被?'c'
?替換。
(3) 最終效果:"aaaabbbcc"
?→?"abc"
。
關鍵總結:
(.)
:抓一個 “基準字符” 并記住(存到組 1);\\1+
:找 “和基準字符相同的、至少 1 個的后續字符”,湊成 “重復序列”;replaceAll(..., "$1")
:用 “基準字符” 替換整個 “重復序列”,實現 “去重”。
2. Date
JDK 8 之前的時間處理:在 Java 8 之前,日期和時間的處理主要依賴?Date
、SimpleDateFormat
、Calendar
?三個核心類(但存在可操作性弱、線程不安全等局限性,因此 JDK 8 后被新的?java.time
?包替代)。
java.util.Date
?類
package demo2;import java.util.Date;
import java.util.Random;public class test4 {public static void main(String[] args) {Random r = new Random();Date d1 = new Date(Math.abs(r.nextInt()));Date d2 = new Date(Math.abs(r.nextInt()));long time1 = d1.getTime();long time2 = d2.getTime();if (time1 > time2) {System.out.println("第一個時間在前面,第二個時間在后面");} else if (time1 < time2) {System.out.println("第二個時間在前面,第二個時間在后面");} else {System.out.println("兩個時間一樣");}}
關鍵邏輯 1:Date d1 = new Date(參數);
① Date
?類的本質是?“封裝一個具體的時間點”,而它最核心的構造函數就是?Date(long date)
—— 接收一個?long
?類型的數字(稱為 “時間戳”),并以此創建對應的時間對象。
② 時間戳的定義:指?從 1970 年 1 月 1 日 00:00:00 GMT(格林威治標準時間)開始,到某個時間點的 “毫秒數”。
比如:
- 時間戳?
0
?→ 對應 1970-01-01 00:00:00 GMT; - 時間戳?
1000
?→ 對應 1970-01-01 00:00:01 GMT(比基準時間多 1 秒,1 秒 = 1000 毫秒); - 時間戳越大,代表的時間越靠后(越 “新”)。
代碼中?
new Date(參數)
?的作用:
用傳入的 “時間戳” 創建一個?Date
?對象,這個對象就代表了該時間戳對應的 “具體時間點”。
比如?d1
?就是一個封裝了 “參數對應時間戳” 的時間對象,d2
?同理。
關鍵邏輯 2:long time1 = d1.getTime();
① Date
?類的?getTime()
?方法是上述構造函數的?反向操作:
② 作用:返回當前?Date
?對象所封裝的?時間戳(毫秒數)。
簡單說:
- 用?
new Date(時間戳)
?可以把 “數字” 變成 “時間對象”; - 用?
getTime()
?可以把 “時間對象” 變回 “數字(時間戳)”。
SimpleDateFormat 類
① 核心作用:實現?Date
(日期對象)?與?String
(字符串)?的雙向轉換:
- 格式化:將?
Date
?轉換為自定義格式的字符串; - 解析:將自定義格式的字符串轉換為?
Date
。
② 構造方法
構造方法 | 說明 |
---|---|
public SimpleDateFormat() | 創建對象,使用默認日期格式 |
public SimpleDateFormat(String pattern) | 創建對象,使用指定的格式模板(如?yyyy-MM-dd ) |
③ 常用方法
方法 | 說明 | 轉換方向 |
---|---|---|
public final String format(Date date) | 將?Date ?格式化為字符串 | Date ?→?String |
public Date parse(String source) | 將字符串解析為?Date | String ?→?Date |
④ 常用符號
符號 | 含義 | 示例(日期?2000-11-11 ) |
---|---|---|
y | 年 | yyyy ?→?2000 |
M | 月 | MM ?→?11 |
d | 日 | dd ?→?11 |
H | 時(24 小時制) | HH ?→?00 (假設為 0 點) |
m | 分 | mm ?→?00 |
s | 秒 | ss ?→?00 |
⑤ 練習:秒殺活動時間范圍校驗程序
題目描述:某平臺開展限時秒殺活動,活動時間為?2023年11月11日 0:0:0
?至?2023年11月11日 0:10:0
。請編寫程序,判斷某筆訂單的時間(2023年11月11日 0:01:00
)是否在秒殺活動的有效時間范圍內,若在范圍內則提示 “參加秒殺活動成功”,否則提示 “參加秒殺活動失敗”。
package demo2;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class test8 {public static void main(String[] args) throws ParseException {String startStr = "2023年11月11日 0:0:0";String endStr = "2023年11月11日 0:10:0";String orderStr = "2023年11月11日 0:01:00";SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");Date startDate = sdf.parse(startStr);Date endDate = sdf.parse(endStr);Date orderDate = sdf.parse(orderStr);long startTime = startDate.getTime();long endTime = endDate.getTime();long orderTime = orderDate.getTime();if (orderTime >= startTime && orderTime <= endTime) {System.out.println("參加秒殺活動成功");} else {System.out.println("參加秒殺活動失敗");}}
}
Calendar 類
① 概論
Calendar
?是代表系統當前時間的日歷對象,可單獨修改、獲取 “年、月、日、時、分、秒” 等時間字段。- 關鍵細節:
Calendar
?是抽象類,不能直接通過?new
?創建對象,需通過靜態方法獲取實例。
② 獲取 Calendar 實例的方法
通過靜態方法?getInstance()
?獲取 “當前系統時間” 的日歷對象:
Calendar cal = Calendar.getInstance();
③ 常用方法及功能
方法簽名 | 說明 |
---|---|
public final Date getTime() | 將?Calendar ?轉換為?Date ?對象(用于和舊版?Date ?類交互)。 |
public final void setTime(Date date) | 將?Date ?對象設置到?Calendar ?中(反向交互)。 |
public long getTimeInMillis() | 獲取當前?Calendar ?對應的時間戳(毫秒數)(從 1970-01-01 00:00:00 GMT 起算)。 |
public void setTimeInMillis(long millis) | 通過 ** 時間戳(毫秒數)** 設置?Calendar ?的時間。 |
public int get(int field) | 獲取日歷中指定字段的值(需配合?Calendar ?常量,如?Calendar.YEAR )。 |
public void set(int field, int value) | 修改日歷中指定字段的值(如設置年份為 2025)。 |
public void add(int field, int amount) | 為日歷中指定字段“增加 / 減少” 指定值(如月份 + 1、天數 - 3)。 |
④?常用字段常量(配合?get/set/add
?使用)
Calendar
?定義了常量表示 “年、月、日” 等字段,常用的有:
Calendar.YEAR
:年Calendar.MONTH
:月(注意:月份從 0 開始,0=1 月,11=12 月)Calendar.DAY_OF_MONTH
:月中的日期Calendar.HOUR_OF_DAY
:24 小時制的 “時”Calendar.MINUTE
:分Calendar.SECOND
:秒