SuperAPI AI Directory

hutool-patterns

Coding & development

View repository

Updated 10-15 21:48

About this skill

Hutool Java Utility Library

Source:https://doc.hutool.cn/
GitHub:https://github.com/chinabugotech/hutool

Capability Boundaries

✅ Strong Suits

  1. StrUtil — format/empty check/truncate/underscore-camelCase conversion, subBetween to extract middle text
  2. CollUtil — isEmpty/intersection/union/subtract/groupBy collection operations
  3. DateUtil — date formatting/parsing (automatically recognizes multiple formats)/offset/time difference/timer
  4. HttpUtil — HTTP GET/POST/file upload (simplified OkHttp/Apache HttpClient)
  5. JSONUtil — lightweight JSON serialization (non-high-throughput scenarios)
  6. SecureUtil — simplified MD5/SHA/AES/RSA/Base64
  7. IdcardUtil — ID card validation (supports 15/18 digits), extract birthday/gender/age/province
  8. Validator — mobile phone number/email/IP/ID card/URL validation
  9. DesensitizedUtil — data masking (mobile phone number/ID card/bank card/address)
  10. ReUtil — simplified regex matching/extraction/replacement

❌ Out of Scope

  1. High-performance JSON → use Jackson/Fastjson2 (Spring Boot default)
  2. High-concurrency HTTP → use OkHttp connection pool
  3. Bean mapping → use MapStruct compile-time generation
  4. Distributed lock → use Redisson

Tool Selection Matrix

Scenario Hutool Guava Apache Commons Java Standard Library
String processing ⭐⭐ ⭐⭐ ⭐⭐⭐ ⭐
Date processing ⭐⭐⭐ — ⭐ ⭐⭐
HTTP client ⭐⭐⭐(simple) — ⭐⭐ ⭐⭐
ID card/mobile phone number ⭐⭐⭐ — ⭐⭐ —
Encryption/decryption ⭐⭐ — ⭐ —
File operations ⭐⭐⭐ ⭐ ⭐⭐⭐ ⭐⭐
JSON ⭐⭐ — — —
Collection operations ⭐⭐ ⭐⭐⭐ ⭐⭐ ⭐⭐

Most Common Mistakes Made by LLMs

# Mistake Correct approach
1 Hand-writing a 30-line regex for ID card validation IdcardUtil.isValidCard("440101...") — includes checksum algorithm
2 String.format() uses %s hard to read StrUtil.format("Hello {}", name) named placeholders are more readable
3 Hand-writing date format conversion/calculation DateUtil.parse(dateStr).offset(DateField.DAY_OF_MONTH, 7)
4 50 lines of Apache HttpClient code to send a GET HttpUtil.get(url) one line does it
5 isEmpty misjudges blank strings use StrUtil.isBlank() instead of isEmpty() — includes blank check
6 Using HttpUtil in high-concurrency scenarios too Use OkHttp connection pool for high concurrency; HttpUtil is only for simple scenarios
7 Using BeanUtil.copyProperties instead of MapStruct BeanUtil is reflection-based (slow at runtime), MapStruct is compile-time generation (fast)
8 Using JSONUtil instead of Jackson JSONUtil is only for lightweight scenarios; use Jackson for production APIs
9 StrUtil.isEmpty(" ") returns false StrUtil.isBlank(" ") returns true
10 SimpleDateFormat is not thread-safe DateUtil.parse() thread-safe, uses ThreadLocal underneath

Core Rules Quick Reference

// ✅ 字符串—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); // 分组

Core Patterns

Pattern 1: Three-step ID card validation

// 1. 快速格式校验 → 2. 完整校验位验证 → 3. 提取信息
if (Validator.isCitizenId(idCard)) {                  // 轻量正则
    if (IdcardUtil.isValidCard(idCard)) {              // 完整校验(含校验位)
        int age = IdcardUtil.getAgeByIdCard(idCard);
        String gender = IdcardUtil.getGenderByIdCard(idCard);
    }
}

Pattern 2: Null value caching protection

// 查询外部 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;
    });
}

Pattern 3: Multi-condition string processing chain

String clean = StrUtil.trim(input);              // 去首尾空白
String named = StrUtil.toCamelCase(clean);       // 转驼峰
List<String> parts = StrUtil.split(named, ',');  // 按逗号分割

Gotchas

  1. isBlank vs isEmpty — isEmpty does not recognize blank strings (spaces/tabs/newlines)
  2. HttpUtil has no connection pool by default — use OkHttp for high-concurrency scenarios; HttpUtil is suitable for simple scenarios
  3. JSONUtil date format defaults to yyyy-MM-dd HH:mm:ss — different from Jackson
  4. BeanUtil.copyProperties is a shallow copy — nested objects are not copied (references are shared)
  5. SecureUtil.sha256() returns a hex string — not byte[]
  6. DateUtil.parse() automatic format detection sometimes misjudges — for explicit formats use parse(dateStr, "yyyy-MM-dd")
  7. IdcardUtil only supports mainland China 18/15-digit ID cards — Hong Kong, Macao, Taiwan/foreign nationals are not supported
  8. Hutool has too many features (500+ classes) — do not import everything, use submodules as needed
  9. DateUtil.parse() is thread-safe — the underlying ThreadLocal holds SimpleDateFormat
  10. CollUtil.groupBy() groups by field — replaces hand-written Map loops

Data Privacy

This skill does not collect, store, or transmit any user data.