Java核心技术36讲--String、StringBuffer、StringBuilder比较

String

String是Java语言非常基础和重要的类,该类提供了构造和管理字符串的各种基本逻辑,是一个典型的不可变类,其被声明为final class,所有属性都是final的。正是由于其不可变性,类似拼接,裁剪字符串都会产生新的String对象。由于字符串操作在编程中的广泛使用,相关操作的效率往往对性能有明显的影响。

StringBuffer

StringBuffer是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,它是 Java 1.5 中新增的,我们可以用append或者add方法,把字符串添加到已有序列的末尾或者指定位置。 StringBuffer本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是 StringBuilder

StringBuilder

StringBuilder在能力上和StringBuffer没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选

小结

String、StringBuffer、StringBuilder比较
  • String的特点: String是一个不可变类,所谓不可变就是一经创建则不能再对其进行改变,对于拼接,裁剪等操作,都会产生新的String对象。

  • StringBuffer的特点: 是一个可变类,对于该类型的字符串进行拼接,裁剪操作,不会产生新的对象,同时它也是线程安全的。

  • StringBuilder的特点: 和StringBuffer类似,对于该类型的字符串进行拼接,裁剪操作,不会产生新的对象,但其不是线程安全的。若是没有线程安全的需要,推荐使用StringBuilder,而不是StringBuffer或者String类。

应用场景

若字符串内容不会经常发生变化,则推荐使用String

若要对字符串频繁进行操作,且要求多线程,则推荐使用线程安全的StringBuffer,例如XML解析、HTTP参数解析与封装;否则使用StringBuilder,例如SQL语句拼装、JSON封装等

字符串设计和实现考量

  • String是不可变类的典型实现,原生的保证了基础线程安全,因为你无法对它内部数据进行任何修改

  • StringBuffer的线程安全是通过把各种修改数据的方法都加上synchronized关键字实现的,这种方法适合常见的线程安全类实现,线程安全会带来一定的性能开销

StringBuffer和StringBuilder实现异同

StringBuffer和StringBuilder底层都是利用可修改的(char,JDK 9 以后是 byte)数组,二者都继承了 AbstractStringBuilder,里面包含了基本操作,区别仅在于最终的方法是否加了synchronized 。

创建StringBuffer和StringBuilder的大小初始化问题

对于这两者来说,内部数组如果初始化的长度太小,则拼接的时候可能需要重新创建足够大的数组,如果初始化时太大,则会造成空间的浪费。

现有的实现可以是,构建时可以使内部数组大小为在初始字符串长度基础上加上16(这意味着,如果在构建对象时没有输入最初的字符串,那么初始值就是16)。如果确定拼接会发生非常多次,而且大概是可预计的,那么就可以指定合适的大小,避免很多次扩容的开销。扩容会产生多重开销,因为要抛弃原有数组,创建新的(可以简单认为是倍数)数组,还要进行arraycopy