hutool-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHutool Java 工具库
Hutool Java 工具库
Capability Boundaries
能力边界
✅ Strong Suits
✅ 强项
- StrUtil — format/空判断/截断/下划线驼峰互转、subBetween 截取中间文本
- CollUtil — isEmpty/intersection/union/subtract/groupBy 集合操作
- DateUtil — 日期格式化/解析(自动识别多格式)/偏移/时间差/计时器
- HttpUtil — HTTP GET/POST/文件上传(简化 OkHttp/Apache HttpClient)
- JSONUtil — 轻量 JSON 序列化(非高吞吐场景)
- SecureUtil — MD5/SHA/AES/RSA/Base64 简化版
- IdcardUtil — 身份证校验(支持15/18位)、提取生日/性别/年龄/省份
- Validator — 手机号/邮箱/IP/身份证/URL 校验
- DesensitizedUtil — 数据脱敏(手机号/身份证/银行卡/地址)
- ReUtil — 正则匹配/提取/替换简化
- StrUtil — format/判空/截断/下划线与驼峰互转、subBetween 截取中间文本
- CollUtil — isEmpty/intersection/union/subtract/groupBy 集合操作
- DateUtil — 日期格式化/解析(自动识别多种格式)/偏移/时间差/计时器
- HttpUtil — HTTP GET/POST/文件上传(简化 OkHttp/Apache HttpClient)
- JSONUtil — 轻量级 JSON 序列化(非高吞吐量场景)
- SecureUtil — 简化版 MD5/SHA/AES/RSA/Base64
- IdcardUtil — 身份证校验(支持15位/18位)、提取生日/性别/年龄/省份
- Validator — 手机号/邮箱/IP/身份证/URL 校验
- DesensitizedUtil — 数据脱敏(手机号/身份证/银行卡/地址)
- ReUtil — 简化版正则匹配/提取/替换
❌ Out of Scope
❌ 不适用范围
- 高性能 JSON → 用 Jackson/Fastjson2(Spring Boot 默认)
- HTTP 高并发 → 用 OkHttp 连接池
- Bean 映射 → 用 MapStruct 编译期生成
- 分布式锁 → 用 Redisson
- 高性能 JSON → 使用 Jackson/Fastjson2(Spring Boot 默认)
- HTTP 高并发 → 使用 OkHttp 连接池
- Bean 映射 → 使用 MapStruct 在编译期生成
- 分布式锁 → 使用 Redisson
工具选择矩阵
工具选择矩阵
| 场景 | Hutool | Guava | Apache Commons | Java 标准库 |
|---|---|---|---|---|
| 字符串处理 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐ |
| 日期处理 | ⭐⭐⭐ | — | ⭐ | ⭐⭐ |
| HTTP客户端 | ⭐⭐⭐(简单) | — | ⭐⭐ | ⭐⭐ |
| 身份证/手机号 | ⭐⭐⭐ | — | ⭐⭐ | — |
| 加解密 | ⭐⭐ | — | ⭐ | — |
| 文件操作 | ⭐⭐⭐ | ⭐ | ⭐⭐⭐ | ⭐⭐ |
| JSON | ⭐⭐ | — | — | — |
| 集合操作 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
| 场景 | Hutool | Guava | Apache Commons | Java 标准库 |
|---|---|---|---|---|
| 字符串处理 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐ |
| 日期处理 | ⭐⭐⭐ | — | ⭐ | ⭐⭐ |
| HTTP客户端 | ⭐⭐⭐(简单) | — | ⭐⭐ | ⭐⭐ |
| 身份证/手机号 | ⭐⭐⭐ | — | ⭐⭐ | — |
| 加解密 | ⭐⭐ | — | ⭐ | — |
| 文件操作 | ⭐⭐⭐ | ⭐ | ⭐⭐⭐ | ⭐⭐ |
| JSON | ⭐⭐ | — | — | — |
| 集合操作 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
LLM最常犯的错误
LLM最常犯的错误
| # | 错误 | 正确做法 |
|---|---|---|
| 1 | 手写身份证校验正则 30 行 | |
| 2 | String.format() 用 | |
| 3 | 手写日期格式转换/计算 | |
| 4 | Apache HttpClient 50行代码发GET | |
| 5 | isEmpty 判断空白字符串误判 | 用 |
| 6 | 高并发场景也用 HttpUtil | 高并发用 OkHttp 连接池,HttpUtil 仅简单场景 |
| 7 | BeanUtil.copyProperties 替代 MapStruct | BeanUtil 是反射(运行时慢),MapStruct 是编译期生成(快) |
| 8 | JSONUtil 替代 Jackson | JSONUtil 仅轻量场景,生产 API 用 Jackson |
| 9 | | |
| 10 | SimpleDateFormat 线程不安全 | |
| # | 错误 | 正确做法 |
|---|---|---|
| 1 | 手写30行身份证校验正则 | |
| 2 | | |
| 3 | 手写日期格式转换/计算 | |
| 4 | 使用50行 Apache HttpClient 代码发送GET请求 | |
| 5 | 使用 isEmpty 判断空白字符串时出现误判 | 使用 |
| 6 | 高并发场景也使用 HttpUtil | 高并发场景使用 OkHttp 连接池,HttpUtil 仅适用于简单场景 |
| 7 | 使用 BeanUtil.copyProperties 替代 MapStruct | BeanUtil 使用反射(运行时较慢),MapStruct 在编译期生成(更快) |
| 8 | 使用 JSONUtil 替代 Jackson | JSONUtil 仅适用于轻量级场景,生产环境 API 使用 Jackson |
| 9 | | |
| 10 | SimpleDateFormat 不是线程安全类 | |
核心规则速查
核心规则速查
java
// ✅ 字符串—isBlank 优于 isEmpty
StrUtil.isBlank(null); // true ✅
StrUtil.isBlank(""); // true
StrUtil.isBlank(" "); // true ← isEmpty 认为 false
StrUtil.isEmpty(" "); // false ❌
// ✅ 字符串—命名占位比 %s 可读
StrUtil.format("Hello {}, 欢迎来到{}!", "张三", "上海");
StrUtil.format("你好, {name}, 欢迎来到{city}!",
MapUtil.of("name", "张三", "city", "上海"));
// ✅ 字符串—截取中间文本
String content = StrUtil.subBetween("prefix_content_suffix", "prefix_", "_suffix"); // "content"
StrUtil.removePrefix("prefix_content", "prefix_"); // "content"
StrUtil.removeSuffix("content_suffix", "_suffix"); // "content"
// ✅ 字符串—分割(自动 trim、忽略空值)
List<String> parts = StrUtil.split("a,b, c ,d", ',', 0, true, true);
// => ["a", "b", "c", "d"]
// ✅ 日期—自动识别多种格式
DateUtil.parse("2025-08-04"); // yyyy-MM-dd
DateUtil.parse("2025/08/04 10:30:00"); // yyyy/MM/dd HH:mm:ss
DateUtil.parse("2025年08月04日"); // 中文日期
// ✅ 日期—计算与比较
DateUtil.offsetDay(new Date(), 7); // 7天后
DateUtil.between(begin, end, DateUnit.DAY); // 间隔天数
DateUtil.beginOfMonth(new Date()); // 月初
DateUtil.endOfMonth(new Date()); // 月末
// ✅ HTTP—简单请求一行搞定
String result = HttpUtil.get("https://api.example.com/data");
HttpUtil.post(url, params); // application/x-www-form-urlencoded
HttpUtil.post(url, jsonBody); // JSON POST
// ✅ HTTP—链式调用(自定义Header/超时)
String result = HttpUtil.createPost(url)
.header("Authorization", "Bearer xxx")
.header("Content-Type", "application/json")
.timeout(5000) // 5秒超时
.body(jsonBody)
.execute()
.body();
// ✅ 身份证—全套处理
IdcardUtil.isValidCard("440101199001011234"); // 校验含校验位
int age = IdcardUtil.getAgeByIdCard(idCard); // 提取年龄
String gender = IdcardUtil.getGenderByIdCard(idCard); // 1=男, 0=女
String birth = IdcardUtil.getBirthByIdCard(idCard); // 19900101
String province = IdcardUtil.getProvinceByIdCard(idCard); // 广东
// ✅ 数据脱敏
DesensitizedUtil.idCardNum(idCard, 1, 2); // 440***********1234
DesensitizedUtil.mobilePhone("13800138000"); // 138****8000
DesensitizedUtil.email("test@example.com"); // t***@example.com
// ✅ 校验
Validator.isMobile("13800138000");
Validator.isEmail("test@example.com");
Validator.isCitizenId("440101199001011234"); // 轻量版身份证校验
// ✅ 集合
CollUtil.isEmpty(list); // 安全的判空(null或空集)
List<String> union = CollUtil.union(list1, list2); // 并集
List<String> inter = CollUtil.intersection(list1, list2); // 交集
Map<String, List<User>> grouped = CollUtil.groupBy(users, User::getStatus); // 分组java
// ✅ 字符串—isBlank 优于 isEmpty
StrUtil.isBlank(null); // true ✅
StrUtil.isBlank(""); // true
StrUtil.isBlank(" "); // true ← isEmpty 认为 false
StrUtil.isEmpty(" "); // false ❌
// ✅ 字符串—命名占位比 %s 可读
StrUtil.format("Hello {}, 欢迎来到{}!", "张三", "上海");
StrUtil.format("你好, {name}, 欢迎来到{city}!",
MapUtil.of("name", "张三", "city", "上海"));
// ✅ 字符串—截取中间文本
String content = StrUtil.subBetween("prefix_content_suffix", "prefix_", "_suffix"); // "content"
StrUtil.removePrefix("prefix_content", "prefix_"); // "content"
StrUtil.removeSuffix("content_suffix", "_suffix"); // "content"
// ✅ 字符串—分割(自动 trim、忽略空值)
List<String> parts = StrUtil.split("a,b, c ,d", ',', 0, true, true);
// => ["a", "b", "c", "d"]
// ✅ 日期—自动识别多种格式
DateUtil.parse("2025-08-04"); // yyyy-MM-dd
DateUtil.parse("2025/08/04 10:30:00"); // yyyy/MM/dd HH:mm:ss
DateUtil.parse("2025年08月04日"); // 中文日期
// ✅ 日期—计算与比较
DateUtil.offsetDay(new Date(), 7); // 7天后
DateUtil.between(begin, end, DateUnit.DAY); // 间隔天数
DateUtil.beginOfMonth(new Date()); // 月初
DateUtil.endOfMonth(new Date()); // 月末
// ✅ HTTP—简单请求一行完成
String result = HttpUtil.get("https://api.example.com/data");
HttpUtil.post(url, params); // application/x-www-form-urlencoded
HttpUtil.post(url, jsonBody); // JSON POST
// ✅ HTTP—链式调用(自定义Header/超时)
String result = HttpUtil.createPost(url)
.header("Authorization", "Bearer xxx")
.header("Content-Type", "application/json")
.timeout(5000) // 5秒超时
.body(jsonBody)
.execute()
.body();
// ✅ 身份证—全套处理
IdcardUtil.isValidCard("440101199001011234"); // 校验含校验位
int age = IdcardUtil.getAgeByIdCard(idCard); // 提取年龄
String gender = IdcardUtil.getGenderByIdCard(idCard); // 1=男, 0=女
String birth = IdcardUtil.getBirthByIdCard(idCard); // 19900101
String province = IdcardUtil.getProvinceByIdCard(idCard); // 广东
// ✅ 数据脱敏
DesensitizedUtil.idCardNum(idCard, 1, 2); // 440***********1234
DesensitizedUtil.mobilePhone("13800138000"); // 138****8000
DesensitizedUtil.email("test@example.com"); // t***@example.com
// ✅ 校验
Validator.isMobile("13800138000");
Validator.isEmail("test@example.com");
Validator.isCitizenId("440101199001011234"); // 轻量版身份证校验
// ✅ 集合
CollUtil.isEmpty(list); // 安全的判空(null或空集)
List<String> union = CollUtil.union(list1, list2); // 并集
List<String> inter = CollUtil.intersection(list1, list2); // 交集
Map<String, List<User>> grouped = CollUtil.groupBy(users, User::getStatus); // 分组核心模式
核心模式
模式 1: 身份证校验三段式
模式 1:身份证校验三段式
java
// 1. 快速格式校验 → 2. 完整校验位验证 → 3. 提取信息
if (Validator.isCitizenId(idCard)) { // 轻量正则
if (IdcardUtil.isValidCard(idCard)) { // 完整校验(含校验位)
int age = IdcardUtil.getAgeByIdCard(idCard);
String gender = IdcardUtil.getGenderByIdCard(idCard);
}
}java
// 1. 快速格式校验 → 2. 完整校验位验证 → 3. 提取信息
if (Validator.isCitizenId(idCard)) { // 轻量正则
if (IdcardUtil.isValidCard(idCard)) { // 完整校验(含校验位)
int age = IdcardUtil.getAgeByIdCard(idCard);
String gender = IdcardUtil.getGenderByIdCard(idCard);
}
}模式 2: 缓存空值防护
模式 2:缓存空值防护
java
// 查询外部 API 时缓存空值,防止穿透
public String queryWeather(String city) {
return cache.get(city, key -> {
String result = HttpUtil.get("https://api.weather.com/" + city);
if (StrUtil.isBlank(result)) {
return "NULL_CACHE"; // 空值标记,缓存5分钟
}
return result;
});
}java
// 查询外部 API 时缓存空值,防止穿透
public String queryWeather(String city) {
return cache.get(city, key -> {
String result = HttpUtil.get("https://api.weather.com/" + city);
if (StrUtil.isBlank(result)) {
return "NULL_CACHE"; // 空值标记,缓存5分钟
}
return result;
});
}模式 3: 多条件字符串处理链
模式 3:多条件字符串处理链
java
String clean = StrUtil.trim(input); // 去首尾空白
String named = StrUtil.toCamelCase(clean); // 转驼峰
List<String> parts = StrUtil.split(named, ','); // 按逗号分割java
String clean = StrUtil.trim(input); // 去首尾空白
String named = StrUtil.toCamelCase(clean); // 转驼峰
List<String> parts = StrUtil.split(named, ','); // 按逗号分割Gotchas
常见陷阱
- isBlank vs isEmpty — isEmpty 不识别空白字符串(空格/tab/换行)
- HttpUtil 默认无连接池 — 高并发场景用 OkHttp,HttpUtil 适合简单场景
- JSONUtil 日期格式默认 yyyy-MM-dd HH:mm:ss — 与 Jackson 不同
- BeanUtil.copyProperties 是浅拷贝 — 嵌套对象不拷贝(引用共享)
- SecureUtil.sha256() 返回 hex 字符串 — 不是 byte[]
- DateUtil.parse() 自动识别格式有时误判 — 明确格式用 parse(dateStr, "yyyy-MM-dd")
- IdcardUtil 仅支持中国大陆18/15位身份证 — 港澳台/外籍不支持
- Hutool 功能太多(500+类) — 不要全部引入,按需使用子模块
- DateUtil.parse() 线程安全 — 底层 ThreadLocal 持有 SimpleDateFormat
- CollUtil.groupBy() 按字段分组 — 替代手写 Map 循环
- isBlank 与 isEmpty 的区别 — isEmpty 无法识别空白字符串(空格/tab/换行)
- HttpUtil 默认无连接池 — 高并发场景使用 OkHttp,HttpUtil 适合简单场景
- JSONUtil 日期格式默认为 yyyy-MM-dd HH:mm:ss — 与 Jackson 不同
- BeanUtil.copyProperties 是浅拷贝 — 不会复制嵌套对象(共享引用)
- SecureUtil.sha256() 返回十六进制字符串 — 而不是 byte[]
- DateUtil.parse() 自动识别格式有时会误判 — 明确指定格式时使用 parse(dateStr, "yyyy-MM-dd")
- IdcardUtil 仅支持中国大陆18位/15位身份证 — 不支持港澳台/外籍身份证
- Hutool 功能众多(500+个类) — 不要一次性全部引入,应按需使用子模块
- DateUtil.parse() 线程安全 — 底层通过 ThreadLocal 持有 SimpleDateFormat
- CollUtil.groupBy() 按字段分组 — 可替代手写 Map 循环
Data Privacy
数据隐私
本技能不收集、存储或传输任何用户数据。
本技能不收集、存储或传输任何用户数据。