开发时经常存在文字占位符替换的需求,目前可以实现该功能的方法多种多样,那究竟哪种的性能最好呢?我调研了String.format的占位符替换,Hutool的CharSequenceUtil.replace的替换以及apache common.text的StringSubstitutor替换性能,用JMH进行了性能测试。
代码如下:

import cn.hutool.core.text.CharSequenceUtil;
import org.apache.commons.text.StringSubstitutor;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 整合SpringBoot基准测试
 */
@BenchmarkMode(Mode.AverageTime) // 测试方法平均执行时间
@OutputTimeUnit(TimeUnit.MICROSECONDS) // 输出结果的时间粒度为微秒
@State(Scope.Thread)
public class JMHFormatTest {

    private static String CODE_BY_FORMAT = "您正在登录%s,验证码:%s(4分钟内有效)";

    private static String CODE_BY_REPLACE = "您正在登录{app},验证码:{code}(4分钟内有效)";

    private static String CODE_BY_SUBSTI = "您正在登录${app},验证码:${code}(4分钟内有效)";

    private static final Map<String, String> valueMap = new HashMap<String, String>(){
        {
            put("app", "abc");
            put("code", "123456");
        }
    };

    public static Integer random()
    {
        int max=3,min=1;
        long randomNum = System.currentTimeMillis();
        return (int) (randomNum%(max-min)+min);
    }


    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder().include(JMHFormatTest.class.getSimpleName())
                .warmupIterations(1).measurementIterations(5).forks(1).build();
        new Runner(options).run();
    }

    @Setup(Level.Trial)//测试级别 执行一次
    public void init() {


    }

    @Benchmark
    @Threads(5)
    public static void testFormat() {
        String res = String.format(CODE_BY_FORMAT, "abc‘’", "123456");
    }

    @Benchmark
    @Threads(5)
    public static void testReplace() {
        String res1 = CharSequenceUtil.replace(CODE_BY_REPLACE, "{app}", "abc");
        String res = CharSequenceUtil.replace(res1, "{code}", "123456");
    }


    @Benchmark
    @Threads(5)
    public static void testStringSubstitutor() {
        StringSubstitutor sub = new StringSubstitutor(valueMap);
        String resolvedString = sub.replace(CODE_BY_SUBSTI);
    }


}

每个方法得到的结果都是一样的,开启五个线程在多线程环境下试一下效果。
image
可以看到String.format的效率最低,执行一次需要0.747微秒,效率最高的是CharSequenceUtil.replace,执行一次只需要0.248微秒。因此,相关场景建议使用CharSequenceUtil.replace