Hutool Hutool
(opens new window)
🏡首页
📖指南
🎢最佳实践
💖支持
💡javaDoc (opens new window)
⏳更新记录 (opens new window)
  • 🍎gitee (opens new window)
  • 🍏github (opens new window)
(opens new window)
🏡首页
📖指南
🎢最佳实践
💖支持
💡javaDoc (opens new window)
⏳更新记录 (opens new window)
  • 🍎gitee (opens new window)
  • 🍏github (opens new window)
  • 快速入门

  • 核心(hutool-core)

    • AI(Hutool-ai)

    • 注解(annotation)

    • 数组(array)

    • JavaBean(bean)

    • 缓存(cache)

    • 类加载器(classloader)

    • 编码解码(codec)

    • 集合(collection)

    • 比较器(comparator)

    • 压缩(compress)

    • 类型转换(convert)

    • 数据(data)

    • 日期时间(date)

    • 异常(exception)

    • 函数(func)

    • IO流(io)

    • 语言特性(lang)

    • Map(map)

    • 数字数学(math)

    • 网络(net)

    • 对象池(pool)

    • 反射(reflect)

    • 正则(regex)

    • 服务提供(spi)

    • 聚合操作(stream)

    • 字符串文本(text)

      • 文本(text)模块简介
      • 字符串工具-StrUtil
      • 字符串模板格式化和解析-StrTemplate
        • 📚简介
        • 名词定义
          • 占位符类型
        • 简单使用
          • 匿名占位符
          • 有名占位符
          • 普通使用
          • 使用Bean对象提供参数值
          • 使用Map提供参数值
          • 使用数组或者列表提供参数
          • 其他技巧
          • 总结
          • 匿名占位符
          • 有名占位符
          • 使用建议
          • 进阶使用
          • 默认值处理器
          • 策略
          • 格式化策略
          • 占位符对应的值不存在时的策略组
          • 占位符对应的值为null时的策略组
          • 解析策略
          • 解析出默认值时的策略组
          • 解析出空字符串时的策略组
          • 解析出"null"字符串时的策略组
          • 使用策略的注意事项
      • 字符序列工具-CharSequenceUtil
      • 字符工具-CharUtil
    • 并发和线程(thread)

    • 树结构(tree)

    • 工具集合(util)

    • XML操作(xml)

  • 定时任务(hutool-cron)

  • 加密(hutool-crypto)

  • 数据库(hutool-db)

  • 扩展(hutool-extra)

  • HTTP(hutool-http)

  • 日志(hutool-log)

  • 配置文件(hutool-setting)

  • JSON(hutool-json)

  • Office办公(hutool-poi)

  • 套接字(hutool-socket)

  • GUI(hutool-swing)

  • 指南
  • 核心(hutool-core)
  • 字符串文本(text)
Hutool
2026-01-03
目录

字符串模板格式化和解析-StrTemplate

# 📚简介

StrTemplate提供了一系列的封装对象用于操作字符串模板的格式化和解析。

字符串模板,或者叫模板字符串,用过SpringBoot的朋友应该不陌生,就是YAML配置文件中的占位符,例如定义这样一个模板字符串I'm ${age} years old., 在这个字符串中,我们可以看到一个特别的部分${age},这就是占位符,可以在程序运行时,将外部age变量的值,直接替换进去, 然后生成结果字符串,例如age=18,则模板字符串格式化的结果为I'm 18 years old.。反过来,根据一个模板字符串和一个结果字符串, 也可以从结果字符串中解析出占位符对应的实际变量值。

请注意,这不是用于json序列化和反序列化的工具, 也不支持${nale | hutool}这样的默认值定义和递归解析。

在hutool之前的版本中,我们提供了StrFormatter、StrMatcher以及PlaceholderParser来辅助完成字符串模板的处理, 而在6.x版本之后, 我们提供了全新的StrTemplate类来处理。

# 名词定义

  1. 用占位符的实际变量值去替换字符串模板中的占位符,最后生成结果字符串,这个过程我们称为格式化;
  2. 根据结果字符串和字符串模板提取出占位符的实际变量值,这个过程我们称为解析;
  3. 转义符:转义符是指,当字符串模板中有占位符,但是我们希望它在结果字符串里出现时使用的标记符。例如字符串模板为"?, 你要干什么?!",其中?为占位符, 但是其实只有第一个?是我们真正需要替换的占位符,第二个?仅仅是字符串的一部分。StrTemplate显然没有那么智能,能自己区分出来, 这个时候就需要用转义符标记一下,代表这个占位符只是普通字符,比如默认的转义符\\(单个反斜杠),最后的字符串模板定义为:”?, 你要干什么\?!“。 转义符是可以自定义的。

# 占位符类型

  1. 匿名占位符:?, {}, ${}, $$$,也叫单占位符,即一个不可拆分整体符号,它常用于格式化,在解析中用得很少;
  2. 有名占位符: {1}, {name}, #{id},它必须拥有前缀和后缀,以及一个有意义的名字,这个名字可以是数字,代表是数组或者列表的下标;

# 简单使用

# 匿名占位符

// 字符串模板
String commonTemplate = "select * from ? where id = ?" ;
// 根据 字符串模板 生成 匿名占位符处理器,我们使用 Builder 模式创建
SinglePlaceholderStrTemplate template = StrTemplate
        // 创建一个匿名占位符处理器
        .of(commonTemplate)
        // 指定匿名占位符
        .placeholder("?")
        // 创建处理器
        .build();

// 格式化
String format = template.format("user", 1001);
// "select * from user where id = 1001"
Console.log(format);

// 解析
// 从 结果字符串中 解析出 格式化时使用的实际值
List<String> matches = template.matches(format);
// ["user", "1001"],是的,很遗憾,解析出的值都是字符串
Console.log(matches);

# 有名占位符

# 普通使用

// 字符串模板
String commonTemplate = "select * from ${table} where id = ${id}";
// 根据 字符串模板 生成 有名占位符处理器,我们使用 Builder 模式创建
NamedPlaceholderStrTemplate template = StrTemplate
    // 创建一个有名占位符处理器
    .ofNamed(commonTemplate)
    // 指定占位符的前缀
    .prefix("${")
    // 指定占位符的后缀
    .suffix("}")
    // 创建处理器
    .build();

// 按顺序传递占位符的值,完成格式化
String format = template.formatSequence("user", 1001);
// "select * from user where id = 1001"
Console.log(format);

// 解析
// 从 结果字符串中 解析出 格式化时使用的实际值
Map<String, String> matches = template.matches(format);
//{"id"="1001", "table"="user"}
Console.log(matches);

// 从 结果字符串中 按顺序解析出 格式化时使用的实际值
List<String> matcheValueList = template.matchesSequence(format);
// ["user", "1001"]
Console.log(matcheValueList);

# 使用Bean对象提供参数值

@Data
public class ParameterBean {
    private String table;
    private Integer id;
}
...

// 格式化
// 构造用于传递参数的bean对象
ParameterBean bean = new ParameterBean();
bean.setTable("user");
bean.setId(1001);
// 字段名必须完全匹配,而且不支持@Alias注解
String format = template.format(bean);
// "select * from user where id = 1001"
Console.log(format);

// 解析出bean对象
// 从 结果字符串中 解析出 格式化时使用的实际值,并填充到传入的bean中,字段名必须完全匹配,而且不支持@Alias注解
ParameterBean parsedBean = template.matches(format, ParameterBean::new);

# 使用Map提供参数值

// 格式化
// 构造用于传递参数的Map
Map<String, Object> parameterMap = MapUtil.<String, Object>builder()
    .put("table", "user")
    .put("id", 1001)
    .build();
// 使用Map传递占位符的值,完成格式化
String format = template.format(parameterMap);
// "select * from user where id = 1001"
Console.log(format);

// 解析
// 从 结果字符串中 解析出 格式化时使用的实际值
Map<String, String> matches = template.matches(format);
//{"id"="1001", "table"="user"}
Console.log(matches);

# 使用数组或者列表提供参数

// 字符串模板,注意下标顺序
String commonTemplate = "select * from ${1} where id = ${0}";
// 根据 字符串模板 生成 有名占位符处理器,我们使用 Builder 模式创建
NamedPlaceholderStrTemplate template = StrTemplate
    // 创建一个有名占位符处理器
    .ofNamed(commonTemplate)
    // 指定占位符的前缀
    .prefix("${")
    // 指定占位符的后缀
    .suffix("}")
    // 创建处理器
    .build();

// 构造参数列表
List<Object> parameterList = Arrays.asList(1001, "user");
// 使用列表传递占位符的值,完成格式化
String format = template.formatIndexed(parameterList);
// "select * from user where id = 1001"
Console.log(format);

// 解析
// 从 结果字符串中 解析出 格式化时使用的实际值
List<String> matcheValueList = template.matchesIndexed(format);
// ["1001", "user"]
Console.log(matcheValueList);

# 其他技巧

  1. isMatches:校验传入的结果字符串是否和模板匹配;
  2. getPlaceholderVariableNames:获取占位符变量名称列表,例如,"{}"返回"{}"、"{name}"返回"name";
  3. getPlaceholderTexts:获取占位符的完整文本列表,例如,"{}"返回"{}"、"{name}"返回"{name}";
  4. formatRawByKey:格式化时,由用户根据占位符变量名,返回参数值;
  5. formatRawBySegment:格式化时,由用户根据解析后的占位符信息对象,返回参数值;
  6. matchesByKey:解析时,给用户传递占位符变量名和提取到的解析值,由用户决定如何使用,会使用默认值相关配置;
  7. matchesRawByKey:解析时,给用户传递占位符变量名和提取到的解析值,由用户决定如何使用,没有任何额外处理;
  8. matchesRawBySegment:解析时,给用户传递解析后的占位符信息对象和提取到的解析值,由用户决定如何使用,没有任何额外处理;

# 总结

# 匿名占位符

不论是格式化还是解析,主要都是根据顺序完成的。 格式化时,可以传递可变参,数组,迭代器; 解析时,可以获得实际值数组或者列表

# 有名占位符

核心在于根据名称映射,数组和列表的下标可以看作一种特殊的名称。 格式化时,可以基于顺序传递参数、可以基于下标传递,可以基于键值对映射结构,可以基于Bean对象; 解析时则是反过来,可以提取出前文提到的数据类型。


# 使用建议

建议将构造好的StrTemplate对象保存起来,就像使用jdk提供的正则表达式对象Pattern一样, StrTemplate也是通过提前”编译“来加快格式化和解析速度的,如果用一次就丢弃给GC,不仅非常浪费,而且性能不佳。


# 进阶使用

# 默认值处理器

有时候,生活就是这样,明明说好要来,都定好位置了,最终却没来, 字符串模板格式化时也会遇到这个问题, 因此我们需要一种方法来处理占位符没有对应的实际值的情况。

此时可以设置默认值,在构造StrTemplate对象时就可以设置。 一共有3种方式:

  1. String defaultValue: 不论占位符是什么,都提供同一个默认值。
  2. UnaryOperator<String> defaultValueHandler:根据传入的占位符名称,由用户决定返回的默认值。
  3. UnaryOperator<String> globalDefaultValueHandler:全局默认的默认值处理器,和defaultValueHandler相同,但是全局生效,后续每个创建的StrTemplate都会使用该默认值处理器。

特别的,如果这三者中有多个都设置了值(是故意的还是不小心?), 则优先使用defaultValue,其次defaultValueHandler,最后globalDefaultValueHandler。


# 策略

有了默认值还是不够,毕竟默认值只能用于占位符对应的参数值不存在, 如果参数值是null,格式化该如何处理? 或者解析时提取出了空字符串,到底是返回空字符串还是null?

有人觉得用空字符串代替就行;
有人站了出来:“可是我希望它把“null”字符串打印出来,这样调试时就能发现潜在的问题”;
又有人说:“我希望把占位符原样打印出来”;
极个别人说:“我希望把占位符里的变量名打印出来”;
更有甚者:“我希望它直接报错”;

因此我们需要一种方法来处理格式化和解析时,占位符没有实际值、值为空字符串或者null的情况,我们使用策略枚举来配置想要的处理方式StrTemplate.Feature。

# 格式化策略
# 占位符对应的值不存在时的策略组
  1. FORMAT_MISSING_KEY_PRINT_WHOLE_PLACEHOLDER:打印完整的占位符,例如"${name}",原样打印"${name}",全局默认策略;
  2. FORMAT_MISSING_KEY_PRINT_DEFAULT_VALUE:打印默认值,如果没有默认值,则抛出异常;
  3. FORMAT_MISSING_KEY_PRINT_NULL:打印默认值,没有默认值,则打印null字符串;
  4. FORMAT_MISSING_KEY_PRINT_EMPTY:打印空字符串;
  5. FORMAT_MISSING_KEY_PRINT_VARIABLE_NAME:打印占位符变量名,例如:"{}"打印"{}"、"{name}"打印"name";
  6. FORMAT_MISSING_KEY_THROWS:直接抛出异常;
# 占位符对应的值为null时的策略组
  1. FORMAT_NULL_VALUE_TO_STR:打印null字符串,全局默认策略;
  2. FORMAT_NULL_VALUE_TO_EMPTY:打印空字符串;
  3. FORMAT_NULL_VALUE_TO_WHOLE_PLACEHOLDER:打印完整的占位符,例如"${name}",原样打印"${name}";
  4. FORMAT_NULL_VALUE_TO_DEFAULT_VALUE:打印默认值,如果没有默认值,则抛出异常;

# 解析策略

解析策略分为三个策略组:解析出默认值,解析出空字符串,解析出"null"字符串。

# 解析出默认值时的策略组
  1. MATCH_KEEP_DEFAULT_VALUE:原样返回,全局默认策略;
  2. MATCH_IGNORE_DEFAULT_VALUE:如果解析值等于默认值,就忽略这个占位变量名,对于返回Map类型,则结果中不包含这个key,对于下标类型数据不生效;
  3. MATCH_DEFAULT_VALUE_TO_NULL:如果解析值等于默认值,就视为null,对于返回Map类型,包含这个key;
# 解析出空字符串时的策略组
  1. MATCH_EMPTY_VALUE_TO_NULL:返回null,全局默认策略;
  2. MATCH_EMPTY_VALUE_TO_DEFAULT_VALUE:转为默认值,如果没有默认值,则转为null;
  3. MATCH_IGNORE_EMPTY_VALUE:忽略该占位变量名,对于返回Map类型,则不包含这个key,对于下标类型数据不生效;
  4. MATCH_KEEP_VALUE_EMPTY:返回空字符串;
# 解析出"null"字符串时的策略组
  1. MATCH_NULL_STR_TO_NULL:返回null,全局默认策略;
  2. MATCH_KEEP_NULL_STR:返回"null"字符串;
  3. MATCH_IGNORE_NULL_STR:忽略该占位变量名,对于返回Map类型,则不包含这个key,对于下标类型数据不生效;
# 使用策略的注意事项
  1. 每个策略组只能选择一个策略,构造StrTemplate时添加同一个组的多个策略,只会保留最后添加的那个;
  2. 每次构造StrTemplate时会将策略设置为全局默认策略,可以提前修改全局默认策略的值;
字符串工具-StrUtil
字符序列工具-CharSequenceUtil

← 字符串工具-StrUtil 字符序列工具-CharSequenceUtil→

Theme by Vdoing | Copyright © 2025-2026 Hutool | Apache-2.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式