StringBuilder、StringBuffer、String这三个的区别,很多文章都有在说。
这边也给大家做一个简要的概述

一:String、StringBuilder、StringBuffer

1:String

String类型是不可变对象,所以我们在每次对 String 类型进行改变的时候,其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。
见源码:

final修饰符
修饰类:不能被继承,
修饰变量:表示该属性一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对对象属性来说其引用不可再变。
修饰方法:说明这种方法提供的功能已经满足当前要求,不需要进行扩展,并且也不允许任何从此类继承的类来重写这种方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。在声明类中,一个 final 方法只被实现一次。

2:StringBuffer

在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer;线程安全

3:StringBuilder

StringBuilder是JDK1.5新增的,注意:不保证同步,该类的设计是用作在StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

4:StringBuffer和StringBuilder为什么可变

见String源码,我们发现
String对象的底层实际上是一个char[]数组:
如图一可见;
用final修饰的对象值可变,但是引用不变,即:value指向不可变,但是value[]数组的值可变,但因为有private关键字对其进行封装达到value[]数组值也不可变的目的

见StringBuffer源码

我们打开父类

可以清晰的看出StringBuffer的value[]没有被private final 修饰
那说明值是可以怎样的,可以被改变的哦。
我们接着看append方法是如何实现改变字符串的

然后进入super父类的方法
我们看看当前的源码

str.getChars()方法即是将str的所有字符拷贝到value[]的后面,返回的还是原来的value数组。
StringBuilder同理。

5:StringBuffer和StringBuilder区别

大家都知道StringBuffer是线程安全的,StringBuilder是非线程安全的

StringBuilder在 Java1.5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,多数情况下建议使用 StringBuilder 类。在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

为什么StringBuffer是线程安全的呢?
见StringBuffer源码:

见StringBuilder源码:

是否出现了一个关键字synchronized,这个关键字大家都认识,这个关键字是为线程同步机制设定的;
这边大概举个例子,如果深究多线程的知识,自行学习
每一个类对象都对应了一把锁,当某个线程A调用类对象B中的synchronized方法C时,必须获得对象B的锁才能够执行C方法,否则线程A阻塞。一旦线程A开始执行C方法,将独占对象B的锁。使得其它需要调用B对象的C方法的线程阻塞。只有线程A执行完毕,释放锁后。那些阻塞线程才有机会重新调用C方法。这就是解决线程同步问题的锁机制。

当看到这个,一说到安全,那大家第一反应,那我就直接用StringBuffer就好了,多线程比StringBuilder安全,如果有多线程需要对同一个字符串缓冲区进行操作的时候,StringBuffer的确是首选。
这样是不是表明StringBuilder和String是不安全咯,String不可变的,线程对于堆中的一个String对象只能读取,不能修改。

注意:看源码我们发现StringBuilder是1.5出来的,说白点前身就是StringBuffer,不考虑线程安全,StringBuilder比StringBuffer效率高,StringBuilder应该是首选。另外,JVM运行程序主要的时间耗费是在创建对象和回收对象上。

6:String,StringBuffer,StringBuilder效率

接着我们看看String那要不要用
可以这样说,某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以某些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

如同下面的情况
String str = “this”+“is”+“a”+“java”;
StringBuffer stringBuffer = new StringBuffer(“this”).append(“is”),append(“a”).append("java);

你会发现,生成str对象会很快,而stringBuffer却不快,因为JVM会自动解析str为
String str = “this”+“is”+“a”+“java”;
String str = “this is a java”;
注意:慢的是对象,就是来自另外的String对象,如下
String str1 = “this”;
String str2 = “is”;
String str3 = “a”;
String str4 = “java”;
这种情况JVM 会正常的按照原来的方式去做。

正常情况下,StringBuffer比String快。
因为StringBuffer有字符串缓冲区的概念。

7:总结三者区别

描述 是否可变 是否线程安全 多线程或单线程操作字符串
String String的值是不可变的,那每次对String的操作都会生成新的String对象,效率低下,且浪费大量优先的内存空间 不可变
StringBuffer StringBuffer是可变的,由于大量的方法用synchronized修饰,属于线程安全,任何对它指向的字符串的操作都不会产生新的对象。 可变 多线程
StringBuilder StringBuilder是1.5引入的,非线程安全的,效率比StringBuffer高。任何对它指向的字符串的操作都不会产生新的对象。 可变 单线程

如果我们在编译阶段能确定的字符串常量,完全没有必要创建String或StringBuffer、StringBuilder对象。可以直接的使用字符串常量的"+“连接操作效率最高。
StringBuffer对象的append效率要远远高于String对象的”+"连接操作。

大致了解了三者区别,具体涉及到class文件,这边没有多做概述,我们现在看看为什么有了StringBuilder,StringBuffer,JDK1.8引入了StringJoiner。

二:StringJoiner

我们经常拼接字符串,考虑线程安全我们就用StringBuffer,非线程安全我们就用StringBuilder。

现在JDK1.8拼接神器StringJoiner来了。
先上个例子:

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(hi);
stringBuilder.append(",");
stringBuilder.append("python");
stringBuilder.append(",");
stringBuilder.append("i am java");
System.out.println(stringBuilder.toString());重复拼接的逗号(,),看起来是不是很傻瓜式的样子,我们看看StringJoiner是如何做的。StringJoiner stringJoiner = new StringJoiner(",");stringJoiner.add("hi");stringJoiner.add("python");stringJoiner.add("i am java");System.out.println(stringJoiner.toString());

我们直接见源码
首先观看构造方法

默认提供了两种构造方法,一个是需要传分隔符的,一个是需要传分隔符,前缀,后缀,我们清楚看到
this.emptyValue = this.prefix + this.suffix;
emptyValue 默认是前缀+后缀组成。

先解释下成员变量
prefix:拼接后的字符串前缀
delimiter:拼接时的字符串分隔符
suffix:拼接后的字符串后缀
value:拼接后的值
emptyValue:空值的情况,value为 null 时返回

看看它给我们提供了哪些可以公共调用的方法,
setEmptyValue 设置空值

toString 主要用于转换String

add 用于添加字符串

merge 从另外一个StringJoiner进行合并

length 长度

上面我们用到了add方法
见源码


StringBuilder,可以清晰的看到,底层还是根据StringBuilder进行封装的,看看多了一个prefix没有,首先它会先添加一个前缀。然后分隔符,字符串

看返回对象仍是StringJoiner,所以后面我们有需求,仍然可以用流式处理。

我们刚才模拟了分隔符,现在我们加上前后缀作为例子看看

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[“);
stringBuilder.append(hi);
stringBuilder.append(",");
stringBuilder.append("python");
stringBuilder.append(",");
stringBuilder.append("i am java");
stringBuilder.append("]“);System.out.println(stringBuilder.toString());// [hi,python,i am java]StringJoiner stringJoiner = new StringJoiner(",","[","]");// 参数一分隔符,参数二前缀,参数三后缀stringJoiner.add("hi");stringJoiner.add("python");stringJoiner.add("i am java");System.out.println(stringJoiner.toString());// [hi,python,i am java]代码是不是很优雅空值如何处理
// 构造方法1StringJoiner stringJoiner = new StringJoiner(",");System.out.println(stringJoiner.toString());
// 构造方法2
StringJoiner stringJoiner = new StringJoiner(",", "[", "]");输出指定字符串
可以通过setEmptyValue StringJoiner stringJoiner = new StringJoiner(",", "[", "]");stringJoiner.setEmptyValue("gaci");System.out.println(stringJoiner.toString());// gaci

三:String.join()

String.join() 主要针对 StringJoiner 又封装了一层的 API,也是Java1.8特性,可以传入动态参数或者迭代器。
见源码:

提供了两个方法:
动态参数

迭代器

仔细阅读之后,此API只能用于简单的拼接,不能添加前后缀以及空值处理。
System.out.println(String.join(",",“hi”,“python”,“i am java”));

的确方便了更多
使用拼间多个相同的分隔符时,使用 StringJoiner,简单处理使用 String.join() 也能完成;针对不同的场景使用不同的 API,这才是最佳最优雅的处理方式。

五:流式处理StringBuilder和StringJoiner

StringBuilder流式处理


final List<String> langs = Arrays.asList("java", "python", "php");final String collectJoin = langs.stream().collect(Collectors.joining(", "));StringBuilder:
final String collectBuilder =langs.stream().collect(Collector.of(StringBuilder::new,(stringBuilder, str) -> stringBuilder.append(str).append(", "),StringBuilder::append,StringBuilder::toString));格式化输出:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String num = numbers.stream().map(i -> i.toString()).collect(Collectors.joining(", "))

StringJoiner是一种收集器,没有实现Collector接口。可以传递定界符,前缀和后缀之外,还可以使用StringJoiner调用Collectors.joining(CharSequence)从Stream创建格式化的输出。
当使用并行流时,这很有用,因为我们在某些时候,将需要并行处理的批处理,StringJoiner就发生了。

JDK1.8特性之StringJoiner相关推荐

  1. 【jdk1.8特性】之Optional

    简介:Optional类是jdk1.8开始为我们提供的一个处理null的类. 代码实例说明: 声明:下面只示例介绍jdk1.8里Optional的用法,对于更高版本jdk里对Optional的进一步优 ...

  2. Sentinel(第三篇)_Springboot2.x+Sentinel监控信息基于MySQL持久化

    前言 根据官方提供的wiki文档,sentinel控制台的实时监控数据,默认提供的存储数据时间为 5 分钟以内的数据.如果我们的需求是需要持久化的,那就需要我们自己定制实现相关的接口. https:/ ...

  3. Java包装类API详解

    在实际程序使用中,程序界面上用户输入的数据都是以字符串类型进行存储的.而程序开发中,我们需要把字符串数据,根据需求转换成指定的基本数据类型,如年龄需要转换成int类型,考试成绩需要转换成double类 ...

  4. Java初阶知识总结

    一.语法部分 java技术结构 J2SE : 表示JAVA标准版 J2EE : java企业版 J2ME : 移动版 java跨平台 基于JVM java是跨平台的 , JVM不是 . 入门程序 每一 ...

  5. 【Java6】Date类/Calendar类,System类/Math类,包装类,集合,泛型,内部类

    文章目录 1.Date类:getTime(),SimpleDateFormat 2.Calendar类:只有子类对象才能向上转型 3.System类:System.exit(0) 4.Math类:ce ...

  6. 看完这篇 HashMap ,和面试官扯皮就没问题了

    来源 | Java 建设者 责编 | Carol 封图 | CSDN 下载自视觉中国 (如果你没有时间细抠本文,可以直接看 HashMap 概述,能让你对 HashMap 有个大致的了解) HashM ...

  7. java学习--基础知识进阶第五天--API、 Object类 System类、日期相关类、包装类正则表达式...

    今日内容介绍 u  Object类 & System类 u  日期相关类 u  包装类&正则表达式 第1章 Object类 & System类 1.1 Object类 1.1. ...

  8. hashmap是有序还是无序_说实话,你要是看完这篇 HashMap ,和面试官扯皮真的就没问题了!

    文章来源:看完这篇 HashMap ,和面试官扯皮就没问题了 原文作者:cxuan 来源平台:微信公众号 (如果你没有时间细抠本文,可以直接看 HashMap 概述,能让你对 HashMap 有个大致 ...

  9. hashmap 允许key重复吗_搞懂 HashMap,这一篇就够了

    HashMap 概述 「如果你没有时间细抠本文,可以直接看 HashMap 概述,能让你对 HashMap 有个大致的了解」. HashMap 是 Map 接口的实现,HashMap 允许空的 key ...

最新文章

  1. SMO学习笔记(三)——效验数据库备份文件
  2. 皮克斯首款VR体验《寻梦环游记》登陆 Oculus Rift
  3. 容易混淆的php函数,个人笔记
  4. Junit源码阅读(四)之自定义扩展
  5. 流之过滤器流(将过滤器串链在一起)
  6. Codeup 墓地——1814: 剩下的树
  7. 【华为解决方案】 华为云架构解决方案
  8. feign调用service_Spring-cloud-eureka使用feign调用服务接口
  9. add函数python怎么用_Python add()函数是如何使用呢?
  10. 28岁程序员期权过亿,彪悍从字节退休,网友:酸了酸了!
  11. JavaScript代码如何在VScode进行调试?
  12. FileUtils工具类的使用
  13. 新知实验室--腾讯云TRTC体验
  14. 《生物信息学:导论与方法》--本体论、分子通路鉴定--听课笔记(十八)
  15. 小学信息技术 用计算机画画 教学目标,三年级下册信息技术教学计划4篇
  16. 3D激光开源项目——BLAM安装使用过程的一些问题
  17. java单根结构_Java语言程序设计中的单根结构
  18. 【前端】HTML详细教程(下篇)
  19. 如何做一个优雅的Pod
  20. Cadence PSpice 模型10:ABM库的控制源型模型介绍与使用方法图文演示

热门文章

  1. 根据气象预警等级颜色获取图片名称,返回对应图片url的方法
  2. C语言山行组合数,高中排列组合基础题-(含答案).doc
  3. SCOM2019创建性能视图
  4. Python练习:爬取B站排行榜数据
  5. Docker部署Oracle11g
  6. 第一次使用git拉取公司代码,报错未能顺利结束 (退出码 128)
  7. STM32:PWM驱动LED达到呼吸灯效果(内含:1.接线原理图/实物图+2.代码部分+3.注意事项/补充知识点部分)
  8. 计算机管理员权限无法粘贴,win10, windows10 复制文件需要管理员权限 才能复制的解决方法...
  9. #1790 : 特工配对
  10. Android自定义View 多边形能力分析控件,雷达图(蛛网)动态实现