Java toString的性能优化方案比较

Java toString的性能优化方案比较

通常toString重写会优先使用StringBuffer来进行append,但jdk1.7以上,已经做了充分优化,让我们通过实际测试数据,来对比下是否String的concat(+)是否真的会差呢?

测试环境,JUnit和JMH(JMH相关资料请自行百度),相关Maven依赖如下:

        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
                <dependency>
            <groupId>org.openjdk.jmhgroupId>
            <artifactId>jmh-generator-annprocessartifactId>
            <version>1.12version>
            <scope>providedscope>
        dependency>

首先基于通用的System的当前时间进行测试,测试代码如下:

public String toStringConcat() {
        return "ToStringTest{" +
                "att1='" + att1 + '\'' +
                ", att2='" + att2 + '\'' +
                ", att3='" + att3 + '\'' +
                '}';
    }

    public String toStringSb() {
        final StringBuffer sb = new StringBuffer("ToStringTest{");
        sb.append("att1='").append(att1).append('\'');
        sb.append(", att2='").append(att2).append('\'');
        sb.append(", att3='").append(att3).append('\'');
        sb.append('}');
        return sb.toString();
    }

    public String toStringStringBuilder() {
        final StringBuilder sb = new StringBuilder("ToStringTest{");
        sb.append("att1='").append(att1).append('\'');
        sb.append(", att2='").append(att2).append('\'');
        sb.append(", att3='").append(att3).append('\'');
        sb.append('}');
        return sb.toString();
    }

下面通过JUnit进行允许测试

/**
     * 功能说明 :junit测试try性能
     * @author  Zain 2016/7/14  10:28
     * @return  result
     * @params
     */
    @Test
    public void simpleTest() throws Exception {
        System.out.println("toStringConcat ---------------------------------");
        long startTime = System.currentTimeMillis();
        try {
            for (int i = 0; i < 1000000; i++) {
                toStringConcat();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("toStringConcat " + (endTime - startTime) + " milliseconds");

        System.out.println("toStringSb ---------------------------------");
        startTime = System.currentTimeMillis();
        try {
            for (int i = 0; i < 1000000; i++) {
                toStringSb();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        endTime = System.currentTimeMillis();
        System.out.println("toStringSb " + (endTime - startTime) + " milliseconds");


        System.out.println("toStringStringBuilder ---------------------------------");
        startTime = System.currentTimeMillis();
        try {
            for (int i = 0; i < 1000000; i++) {
                toStringStringBuilder();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        endTime = System.currentTimeMillis();
        System.out.println("toStringStringBuilder " + (endTime - startTime) + " milliseconds");


    }
代码很简单,直接给测试结果:
toStringConcat ---------------------------------
toStringConcat 80 milliseconds
toStringSb ---------------------------------
toStringSb 374 milliseconds
toStringStringBuilder ---------------------------------
toStringStringBuilder 146 milliseconds
当然,每次运行结果可能不一样,由于JVM“热身”的原因,我们调整下运行顺序,将String的concat放到最后,运行结果如下:
toStringSb ---------------------------------
toStringSb 370 milliseconds
toStringStringBuilder ---------------------------------
toStringStringBuilder 235 milliseconds
toStringConcat ---------------------------------
toStringConcat 69 milliseconds
这里已经可以看到曾经邪恶的+,貌似更加高效,下面用JMH测试进一步有效验证。
测试代码如下:
   @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void toStringConcatBenchmark() {
        int j = 3;
        try {
            for (int i = 0; i < 1000000; i++) {
                toStringConcat();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void toStringSbBenchmark() {
        int j = 3;
        for (int i = 0; i < 1000000; i++) {
            try {
                toStringSb();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void toStringStringBuilderBenchmark() {
        int j = 3;
        for (int i = 0; i < 1000000; i++) {
            try {
                toStringStringBuilder();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
JMH允许代码:
    /**
     * 功能说明 :JMH测试try性能
     * @author  Zain 2016/7/14  10:29
     * @return  result
     * @params
     */
    @Test
    public void benchmarkTest() throws Exception {
        Options opt = new OptionsBuilder()
                .include(ToStringTest.class.getSimpleName())
                .forks(1)
                .build();
        new Runner(opt).run();
    }
运行结果:
# Run complete. Total time: 00:02:10
第一次
Benchmark                                     Mode  Cnt  Score    Error   Units
ToStringTest.toStringConcatBenchmark         thrpt   20  0.029 ±  0.001  ops/ms
ToStringTest.toStringSbBenchmark             thrpt   20  0.006 ±  0.001  ops/ms
ToStringTest.toStringStringBuilderBenchmark  thrpt   20  0.008 ±  0.001  ops/ms

第二次
Benchmark                                     Mode  Cnt  Score    Error   Units
ToStringTest.toStringConcatBenchmark         thrpt   20  0.029 ±  0.001  ops/ms
ToStringTest.toStringSbBenchmark             thrpt   20  0.006 ±  0.001  ops/ms
ToStringTest.toStringStringBuilderBenchmark  thrpt   20  0.007 ±  0.001  ops/ms
综上,还是傻傻的什么都不想,用最原始的方式吧,哈哈...

你可能感兴趣的:(java-基础)