Java入门系列之StringBuilder、StringBuffer(三)

前言

上一节我们讲解了字符串的特性,除了字符串类外,还有两个我们也会经常用到的类,那就是StringBuffer和StringBuilder。因为字符串不可变,所以我们每次对字符串的修改比如通过连接concat、trim等都会创建一个新的字符串对象,那么我们如何在不创建字符串垃圾(大量临时的字符串)的 情况下操作字符串呢?答案则是使用StringBuffer和StringBuilder,StringBuffer是旧类,但是在Java 5中新增了StringBuilder,并且在Enum,Generics等和Java中的Autoboxing方面进行了重大改进。

StringBuffer VS StringBuilder

String和StringBuffer之间的主要区别是String是不可变的,而StringBuffer、StringBuilder可变,这也就意味着我们可以在创建StringBuffer对象时修改它而不创建任何新对象,这个可变属性使StringBuffer成为处理Java中的字符串的理想选择,同时,这种可变性更加节省时间并且资源消耗更少。当然我们可以通过toString将StringBuffer转换为String。这两个类几乎相同,它们使用具有相同名称的方法返回相同的结果,我们看看StringBuffer和StringBuilder源码中的Append方法即可知其区别:

   @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

线程安全:StringBuffer方法是同步的,这意味着一次只能有一个线程调用StringBuffer实例的方法。 另一方面,StringBuilder方法不同步,因此多个线程可以调用StringBuilder类中的方法而不会被阻塞。所以我们得出结论,StringBuffer是一个线程安全的类,而StringBuilder则不是。如果我们正在处理使用多线程的应用程序,那么使用StringBuilder可能会有线程不安全风险。

速度:StringBuffer实际上比StringBuilder慢两到三倍。 这背后的原因是StringBuffer同步,一次只允许一个对象在一个对象上执行,导致代码执行速度慢得多。

StringBuffer和StringBuilder都有相同的方法(除了StringBuffer类中的synchronized方法声明外),以下为常见方法:

  • append()
  • insert()
  • replace()
  • delete()
  • reverse()

我们通过如下示例来使用上述几个常用方法:

public class Main {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Buffer no 1");
        System.out.println(sb);

        sb.append(" - and this is appended!");
        System.out.println(sb);
        sb.insert(11, ", this is inserted");
        System.out.println(sb);
        sb.replace(7, 9, "Number");
        System.out.println(sb);
        sb.delete(7, 14);
        System.out.println(sb);
        sb.reverse();
        System.out.println(sb);
    }
}

接下来我们来对String、StringBuffer、StringBuilder进行性能测试。

        String concatString = "concatString";
        StringBuffer appendBuffer = new StringBuffer("appendBuffer");
        StringBuilder appendBuilder = new StringBuilder("appendBuilder");
        long timerStarted;

        timerStarted = System.currentTimeMillis();
        for (int i = 0; i < 50000; i++) {
            concatString += " another string";
        }
        System.out.println("Time needed for 50000 String concatenations: " + (System.currentTimeMillis() - timerStarted) + "ms");

        timerStarted = System.currentTimeMillis();
        for (int i = 0; i < 50000; i++) {
            appendBuffer.append(" another string");
        }
        System.out.println("Time needed for 50000 StringBuffer appends: " + (System.currentTimeMillis() - timerStarted) + "ms");

        timerStarted = System.currentTimeMillis();
        for (int i = 0; i < 50000; i++) {
            appendBuilder.append(" another string");
        }
        System.out.println("Time needed for 50000 StringBuilder appends: " + (System.currentTimeMillis() - timerStarted) + "ms");

如上打印输出因Java虚拟机而异,从如上基准测试中我们还是可以看出StringBuilder是字符串操作中最快的,次之StringBuffer,它比StringBuilder慢1倍多,最后是String这是字符串操作中最慢的。使用StringBuilder的时间比普通的String快一系列。那么是不是说明我们对字符串操作时,完全摒弃使用字符串呢?当然不是,凡是没绝对,比如对字符串只是简单操作,直接使用字符串也没有多大性能损耗。

String:不可变(这意味着更多的内存消耗)并且在进行字符串操作时非常慢,但是线程安全。

StringBuffer:可变且内存有效,并且是线程安全的。 与更快的StringBuilders相比,它们的下降速度是速度。

StringBuilder:可变的且内存有效,它们是字符串操作中最快的,但不幸的是它不是线程安全的。

总结

本节我们比较了StringBuffer和StringBuilder的区别,算是做一个笔记,没有什么理解难点,如果我们基于以上事实结论考虑,我们始终会做出正确的选择!

原文地址:https://www.cnblogs.com/jeffckywang/p/11372119.html

时间: 2024-10-07 17:30:53

Java入门系列之StringBuilder、StringBuffer(三)的相关文章

java面试题String,StringBuilder,StringBuffer

面试的经历中,相信大家都经常被问到这三者的区别,说到String我相信绝大多数的人都会说:"String是不可变的,final修饰的",你会看到面试官微微猥琐一笑,接着问到:"final修饰的类就是不可变的吗,那StringBuilder和StringBuffer不是final修饰的?" 1. 先来说说String 看下JDK1.7 String成员变量的源码 /** * @author Lee Boynton * @author Arthur van Hoff *

Java入门系列之包装类(四)

前言 上一节我们讲解了StringBuilder VS StringBuffer以及二者区别,本节我们来讲解包装类. 包装类 我们知道在Java中有8中基本数据类型,分为数值类型:byte.short.int.long.float.double.字符类型:char.布尔类型:bool,那么什么是包装类呢?包装类是8种基本数据类型的对象表示,而且8种包装类和字符串对象一样是不可变且final(不可通过继承或扩展破坏不可变性)的.我们通过查看int的包装类型Integer可知,如下: 如下为基本数据

Java基础之String,StringBuilder,StringBuffer

在创建字符串的时候总是习惯性的使用String str = "...";,str = str+"abcd";也有听说过StringBuffer,StringBuilder,但是压根就没想过要去了解过. String乍一看创建的很方便,其实在字符串比较多的时候或者说创建了多个字符串的时候就会出现很大的问题,因为String在新创建字符串的时候是在内存里面新开辟了一块内存去存储这个字符串,因为String是静态的,之所以我们看起来是动态的,那是因为JVM把我们欺骗了,在

Java入门系列:处理Json格式数据

本节主要讲解: 1)json格式数据处理方法 2)第三方工具包的使用方法 3)java集合数据类型 [项目任务] 编写一个程序,显示未来的天气信息. [知识点解析] 为了方便后面代码的分析,先需要掌握几个相关的知识. 1.什么是json格式数据 从结构上看,我们所见到的所有的数据(data)最终都可以分解成三种类型: 第一种类型是标量(scalar),也就是一个单独的字符串(string)或数字(numbers),比如"北京"这个单独的词. 第二种类型是序列(sequence),也就是

Java入门系列:实例讲解ArrayList用法

本文通过实例讲解Java中如何使用ArrayList类. Java.util.ArrayList类是一个动态数组类型,也就是说,ArrayList对象既有数组的特征,也有链表的特征.可以随时从链表中添加或删除一个元素.ArrayList实现了List接口. 大家知道,数组是静态的,数组被初始化之后,数组长度就不能再改变了.ArrayList是可以动态改变大小的.那么,什么时候使用Array(数组),什么时候使用ArrayList?答案是:当我们不知道到底有多少个数据元素的时候,就可使用Array

Java入门系列(十)Java IO

总体而言,java的读写操作又分为两种:字符流和字节流. 什么是流? 流是一个抽象的概念.当Java程序需要从数据源读取数据时,会开启一个到数据源的流.数据源可以是文件,内存或者网络等.同样,当程序需要输出数据到目的地时也一样会开启一个流,数据目的地也可以是文件.内存或者网络等.流的创建是为了更方便地处理数据的输入输出. 那么字节流和字符流又有什么区别呢? 1.字节流也称为原始数据,需要用户读入后进行相应的编码转换.而字符流的实现是基于自动转换的,读取数据时会把数据按照JVM的默认编码自动转换成

Java入门系列-04-java中的变量

这篇文章为你搞懂三个问题 什么是变量? 如何使用变量? 变量命名有哪些规范? 变量 计算机的内存类似于人的大脑,电脑使用内存来存储计算所需要的数据. 内存像旅馆一样,不同的房间类型对应不同的数据类型,内存存储数据时会根据数据的需求为它申请一块合适的空间.用于存储数据的这个空间就是变量. 变量名 内存地址 值 name 0x5c2a0c3f.. 张三 age 0xcd4d72a... 10 变量名.内存和存储的值如上表↑ 可以看到内存地址长而不方便记忆,但是变量名可以像给一个人起外号一样,方便记忆

Java入门系列-14-深入类和对象

这篇文章用大量的代码帮你搞懂:值传递和引用传递.构造方法.方法重载.static关键字的使用 方法参数传递-值传递和引用传递 1.值传递 敲一敲: /** * 使用方法交换两个变量的值 * @author Jack * */ public class Swap { public static void main(String[] args) { int a=10; int b=8; Swap swap=new Swap(); swap.swap(a, b); System.out.println

Java入门系列-08-选择结构

这篇文章为你搞懂2个问题 if-else选择结构的使用? switch 的使用? 前面我们学习的代码都是直上直下的执行,还不会"拐弯",这篇文章带大家来看一下会"拐弯"的代码--选择结构,顾名思义就有选择性的执行代码. if-else 选择结构 简单if结构 只有一种执行情况,表达式结果为true时执行结构内代码片段,为false时不执行 语法: if(表达式){ 代码片段 } 敲一敲: import java.util.Scanner; public class