Java toString的性能优化方案比较

本文通过JUnit和JMH对比了Java中使用String concat、StringBuffer和StringBuilder实现toString方法的性能。测试结果显示,在JDK 1.7及更高版本中,String concat方式表现最优。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java toString的性能优化方案比较

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

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

        <!-- 测试部分-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
                <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <version>1.12</version>
            <scope>provided</scope>
        </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性能优化常见方法和技术手段 Java作为一种广泛使用的编程语言,在实际开发过程中可能会遇到性能瓶颈。为了提高程序效率,可以从多个方面入手进行性能优化。 #### 1. JVM调优 由于Java运行于JVM虚拟机之上,其表现直接受到JVM配置的影响。通过调整垃圾回收器(GC)、堆内存小以及其他相关参数,可以在很程度上改善应用程序的性能[^3]。例如,合理设置新生代和老年代的比例、选择适合应用场景的垃圾收集算法(如G1 GC或CMS GC),都是常见的优化措施。 #### 2. 数据结构的选择 不同的数据结构适用于不同场景,错误的数据结构可能导致不必要的开销。例如,`ArrayList`相较于`LinkedList`更适合频繁随机访问的情况;而在读操作远多于写操作的情况下,`CopyOnWriteArrayList`则能有效减少锁竞争带来的延迟[^4]。 #### 3. 并发处理 现代计算机通常具备多核处理器的能力,因此充分利用多线程技术对于提升吞吐量至关重要。然而,过度依赖同步机制可能反而会成为瓶颈所在。开发者应当熟悉各种高级并发工具类(如`ConcurrentHashMap`, `CountDownLatch`)以及无锁/轻量级锁定策略的应用场合。 #### 4. 中间件优化 中间件层面上也有许多可以改进的地方来增强整体系统的响应速度和服务质量。这包括但不限于数据库连接池管理、缓存策略制定等方面的工作[^2]。 #### 5. 架构设计上的考量 良好的软件架构本身就是一种重要的性能保障因素之一。微服务化改造、分库分表等型重构项目虽然耗时较长但往往收益巨; 同样地, API网关模式下统一认证授权流程也可以带来明显的效能增益。 #### 6. 编码习惯与实践技巧 除了上述宏观层面的技术手段外,日常编写代码时的一些细节同样不容忽视。比如避免创建过多临时对象以免增加GC负担;利用StringBuilder代替字符串拼接运算符+以获得更好的执行效果等等[^1]。 ```java // 使用 StringBuilder 进行字符串拼接示例 public String concatenateStrings(List<String> strings){ StringBuilder sb = new StringBuilder(); for(String s : strings){ sb.append(s); } return sb.toString(); } ``` #### 7. 测试与监控 最后也是最重要的一环就是持续不断地测试现有解决方案的效果并借助专业的APM(Application Performance Management) 工具来进行实时监测分析找出潜在问题根源所在从而采取针对性更强的新一轮迭代升级行动直至达到预期目标为止^。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值