Java 黑马程序员学习笔记(进阶篇6)

常用的 API

1. 正则表达式

(1) 题目:贪婪爬取和非贪婪爬取

① 贪婪爬取:爬取数据的时候尽可能的多获取数据

② 非贪婪爬取:爬取数据的时候尽可能的少获取数据

③ Java中默认的是贪婪爬取

④ + 后面加上 ? 可以转变为非贪婪爬取

(2) 捕获分组

捕获分组通过 (...)将部分正则表达式包裹,会保存该组的匹配结果; 后续可通过 \\nn为分组编号,从1开始)反向引用这组结果,实现 "重复使用已匹配的内容"。

需求 1:单字符首尾一致(如 a123ab456b

正则表达式(. ).+\\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 个捕获组)
  • (.)( 表示创建捕获组,. 匹配任意单个字符 (比如 ab& 等)。
  • 这部分的作用:捕获一个 "基础字符",后续会重复使用这个字符。
  • 编号:因为是第 2 个出现的左括号(第一个左括号是外层的 (),所以是第 2 组,后续用 \\2 引用。
② 中间层:\\2+
  • \\2:反向引用第 2 组捕获的 "基础字符"(比如第 2 组捕获了 a\\2 就代表 a)。
  • +:量词,表示 "至少出现 1 次 "(和 * 不同,* 允许 0 次,+ 必须 1 次及以上)。
  • 组合起来:\\2+ 表示 "基础字符至少重复 1 次 "(比如基础字符是 a,就匹配 aaaaaaaaa 等)。
③ 外层分组:((.)\\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 之前,日期和时间的处理主要依赖 DateSimpleDateFormatCalendar 三个核心类(但存在可操作性弱、线程不安全 等局限性,因此 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 格式化为字符串 DateString
public Date parse(String source) 将字符串解析为 Date StringDate

④ 常用符号

符号 含义 示例(日期 2000-11-11
y yyyy2000
M MM11
d dd11
H 时(24 小时制) HH00(假设为 0 点)
m mm00
s ss00
⑤ 练习:秒杀活动时间范围校验程序

题目描述 :某平台开展限时秒杀活动,活动时间为 2023年11月11日 0:0:02023年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:秒
相关推荐
好学且牛逼的马9 分钟前
MyBatis-Plus的深度解析
java
苏纪云10 分钟前
数据结构<C++>——数组
java·数据结构·c++·数组·动态数组
典则32 分钟前
STM32FreeRtos入门(五)——同步互斥与通信
java·jvm·stm32
你不是我我33 分钟前
【Java 开发日记】我们来讲一讲阻塞队列及其应用
java·开发语言
互联网中的一颗神经元34 分钟前
小白python入门 - 9. Python 列表2 ——从基础操作到高级应用
java·开发语言·python
大厂码农老A38 分钟前
我带的外包兄弟放弃大厂转正,薪资翻倍入职字节
java·后端·面试
摇滚侠1 小时前
全面掌握 PostgreSQL 关系型数据库,PostgreSQL 介绍,笔记02
数据库·笔记·postgresql
摇滚侠1 小时前
Spring Boot3零基础教程,生命周期监听,自定义监听器,笔记59
java·开发语言·spring boot·笔记
讽刺人生Yan1 小时前
RFSOC学习记录(一)RF data converter总览
学习·fpga开发·rfsoc
凯子坚持 c1 小时前
Llama-2-7b在昇腾NPU上的六大核心场景性能基准报告
java·开发语言·llama