资讯专栏INFORMATION COLUMN

String:String / StringBuffer / StringBuilder 三者的功能

icattlecoder / 2116人阅读

摘要:不指定容量会显著降低性能一般使用在方法内部来完成类似功能,因为是线程不安全的,所以用完以后可以丢弃。主要用在全局变量中相同情况下使用相比使用仅能获得左右的性能提升,但却要冒多线程不安全的风险。

String 作为最基础的引用数据类型,日常的开发中被大量的使用。基于不可变的特性,一旦被过度地使用,堆内存就会负荷不堪,甚至影响性能,为此,Java 设计者特意为 String 在方法区中开辟了字符串常量池,以减少 String 的实例创建,然而,在面对大数量的情况下,字符串常量池也未必能解决问题,因此,AbstractStringBuilder 应运而生,就是为了解决 String频繁创建而引发的内存性能下降的问题。

带着两个问题,去看看String / StringBuffer / StringBuilder 的区别

String vs AbstractStringBuilder

StringBuffer vs StringBuilder

String / StringBuffer / StringBuilder 的使用策略

String vs AbstractStringBuilder

扩容机制

String

不可变性:重新创建一个对象

String 底层代码实现:

String 类被 final 修饰,该类不能被继承

value[] 属性 被final 修饰 ,引用不能修改

public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final char value[];   //

    /** Cache the hash code for the string */
    private int hash; // Default to 0```
    
    //other codes

测试代码:


 String str = new String("a");
        str = str  + “b” ;

图示:

AbstractStringBuilder

可变性

AbstractStringBuilder 底层代码实现:

value[] 相对于 String ,没有被final修饰

append("String") 返回时对象本身,不会创建新的对象

abstract class AbstractStringBuilder implements Appendable, CharSequence {
     /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;
    
    
    // other codes 
    
    
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    
    //other codes
}

测试代码:

  StringBuffer sb = new StringBuffer("a");
               sb.append("b");

图示:

性能比较

public class StringBufferWithStringBuilder {

    public void testString() {
        long start = System.currentTimeMillis();
        String str = null;
        for (int i = 0; i < 20000; i++) {
            str = str + i + ",";
        }
        System.out.println(System.currentTimeMillis() - start); 
    }

    public void testStringBuffer() {
        long start = System.currentTimeMillis();

        StringBuffer sbuf = new StringBuffer();
        for (int i = 0; i < 20000; i++) {
            sbuf.append(i + ",");
        }
        System.out.println(System.currentTimeMillis() - start);
    }

    public void testStringBulider() {
        long start = System.currentTimeMillis();

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 20000; i++) {
            builder.append(i + ",");
        }
        System.out.println(System.currentTimeMillis() - start);
    }

    @Test
    public void test(){
        testString();
        testStringBuffer();
        testStringBulider();
    }
    
}

通过测试数据得知,在性能和效率上:StringBuilder>StringBuffer>String

原因在于:

String 每执行一次 + 重载运算符,必须创建一个新的对象

StringBuilder 与 StringBuffer相比,少了同步锁

StringBuffer vs StringBuilder

线程安全

StringBuffer 是线程安全的

StringBuilder 是线程不安全

底层实现: StringBuffer 通过 synchronized 关键字的修饰,保证了资源不会被抢占,从而确保了线程安全

 /**
     * @since      1.5
     */
    @Override
    public synchronized void trimToSize() {
        super.trimToSize();
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */
    @Override
    public synchronized void setLength(int newLength) {
        toStringCache = null;
        super.setLength(newLength);
    }
String / StringBuffer / StringBuilder 的使用策略

基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer

不要使用String类的"+"来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则

为了获得更好的性能,在构造 StringBuffer 或 StringBuilder 时应尽可能指定它们的容量。当然,如果你操作的字符串长度(length)不超过 16 个字符就不用了,当不指定容量(capacity)时默认构造一个容量为16的对象。不指定容量会显著降低性能

StringBuilder一般使用在方法内部来完成类似"+"功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer主要用在全局变量中

相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67220.html

相关文章

  • Java中StringStringBuilder,StringBuffer三者区别

    摘要:所以如果要进行的操作是多线程的,那么就要使用,但是在单线程的情况下,还是建议使用速度比较快的。总结一下适用于少量的字符串操作的情况适用于单线程下在字符缓冲区进行大量操作的情况适用多线程下在字符缓冲区进行大量操作的情况 [TOC] 原文链接:[https://www.cnblogs.com/su-fe...]: 这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面 1、首先说...

    tinna 评论0 收藏0
  • StringStringBuilder、StringBuffer爱恨情仇

    摘要:当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用而不用的,就是速度的原因。 第三阶段 JAVA常见对象的学习 StringBuffer和StringBuilder类 (一) StringBuffer类的概述 (1) 基本概述 下文以StringBuffer为例 前面我们用字符串做拼接,比较耗时并且也耗内存(每次都会构造一个新的string对象),而这种拼接操作又...

    stormjun 评论0 收藏0
  • Java String类笔记

    摘要:这两个操作符都是编译器默认引入了类,最后都调用方法返回对象,临时对象被回收,因此效率极为低下 Java String类笔记 声明 文章均为本人技术笔记,转载请注明出处https://segmentfault.com/u/yzwall String的不可变性 String的不可变性 // String declaration public final class String ...

    Vicky 评论0 收藏0
  • 浅谈 Java 字符串(String, StringBuffer, StringBuilder)

    摘要:与类基本相同,都是可变字符换字符串序列,不同点是是线程安全的,是线程不安全的。和区别在大部分情况下是线程安全的可变字符序列。在程序中可将字符串缓冲区安全地用于多线程。 转载自飘过的小牛 我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一、定义 showImg(/...

    ShowerSun 评论0 收藏0
  • Java中String,StringBuilder,StringBuffer区别以及使用场景

    本文原创文章,转载注明出处,博客地址 https://segmentfault.com/u/to... 第一时间看后续精彩文章。觉得好的话,顺手分享到朋友圈吧,感谢支持。 笔者经常忘记三者之间的区别,下面自己总结一番,画一个表格来展示 Item +区别 多线程 性能 使用场景 优化 String 不可变类,重新创建字符串 不安全 拼接时,性能差 操作少量数据,字符串不变时 无 St...

    QiuyueZhong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<