常用的 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:"口吃" 字符去重
将包含重复字符的字符串(如 我要学学编编编编编程程程程程程
),替换为单个重复字符 ,最终得到 我要学编编程
。
java
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
类
java
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
)是否在秒杀活动的有效时间范围内,若在范围内则提示 "参加秒杀活动成功",否则提示 "参加秒杀活动失败"。
java
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()
获取 "当前系统时间" 的日历对象:
java
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
:秒