话接上回,继续核心类与API的学习,这次介绍StringBuffer/StringBuilder/StringJoiner类。StringBuffer和StringBuilder是我们学习的重点,建议对比学习,做好区分。

一、StringBuffer类

1、概述

1)问题
由于 String 类是final 类型的,所以使用 String 定义的字符串是一个常量,一旦创建,其内容和长度是不可改变的。如果需要对一个字符串进行修改,只能创建新的字符串。
2)解决
使用 StringBuffer 类(也称字符串缓冲区)来操作字符串。

==StringBuffer 类和 String 类最大的区别在于它的内容和长度都是可以改变的==。StringBuffer 类似一个字符容器,当在其中添加或删除字符时,所操作的都是这个字符容器,因此并不会产生新的 StringBuffer 对象。

2、创建StringBuffer类对象

2.1 三种方式

1)StringBuffer() 构造一个空的字符串缓冲区,并初始化为 16 个字符的容量。
2)StringBuffer(int length) 创建一个空的字符串缓冲区,并初始化为指定长度 length 的容量。
3)StringBuffer(String str) 创建一个字符串缓冲区,并将其内容初始化为指定的字符串内容 str,字符串缓冲区的初始容量为 16 加上字符串 str 的长度。

2.2 案例

看文字不好理解的话就看如下案例

1
2
3
4
5
6
7
8
9
10
11
12
13
// 定义一个空的字符串缓冲区,含有16个字符的容量
StringBuffer str1 = new StringBuffer();
// 定义一个含有10个字符容量的字符串缓冲区
StringBuffer str2 = new StringBuffer(10);
// 定义一个含有(16+4)的字符串缓冲区,"青春无悔"为4个字符
StringBuffer str3 = new StringBuffer("青春无悔");
/*
*输出字符串的容量大小
*capacity()方法返回字符串的容量大小
*/
System.out.println(str1.capacity()); // 输出 16
System.out.println(str2.capacity()); // 输出 10
System.out.println(str3.capacity()); // 输出 20

注:当不指定容量(capacity)时默认构造一个容量为16的对象。

3、String与StringBuffer对象的转换

直接看案例

1
2
3
4
5
6
7
8
9
10
11
public class StringBufferDemo1 {
public static void main(String[] args){
String s = "abc"; //String转StringBuffer
StringBuffer s1= new StringBuffer(s);
System.out.println(s1); //abc

StringBuffer str=new StringBuffer("javaee");
String str1=str.toString(); //StringBuffer转String(toString方法)
System.out.println(str1); //javaee
}
}

4、StringBuffer类常用方法

常用的有append、delete、insert、replace、reverse、toString、setCharAt(修改指定位置index处的字符)等方法,其他方法和String类似,可自行对照来看。直接看懂以下案例即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class StringBufferDemo1 {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("Happy New Year!");
s.append(" 你好 2023!");
System.out.println(s); //Happy New Year! 你好 2023!
s.insert(6, "happy ");
System.out.println(s); //Happy happy New Year! 你好 2023!
s.replace(6, 11, "new"); //左闭右开,下标0开始
System.out.println(s); //Happy new New Year! 你好 2023!
s.delete(5, 9);
System.out.println(s); //Happy New Year! 你好 2023!
s.reverse(); //翻转
System.out.println(s); //!3202 好你 !raeY weN yppaH
s.setCharAt(1, '2');
System.out.println(s); //!2202 好你 !raeY weN yppaH
String str=s.toString(); //StringBuffer转String(toString方法)
System.out.println(str); //!2202 好你 !raeY weN yppaH
System.out.println(s.length()); //24,返回长度,和String一样
}
}

二、StringBuilder类

1、概述

StringBuilder 类是 JDK 1.5 新增的类,它也代表==可变字符串==对象。实际上,StringBuilder 和 StringBuffer 功能基本相似,方法也差不多。不同的是,==StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高==。

通常情况下,如需创建一个内容可变的字符串对象,应优先考虑使用 StringBuilder 类。

2、创建StringBuilder类对象

2.1 三种方式

1)StringBuilder 构造一个空的字符串缓冲区,并初始化为 16 个字符的容量。
2)StringBuilder(int length) 创建一个空的字符串缓冲区,并初始化为指定长度 length 的容量。
3)StringBuilder(String str) 创建一个字符串缓冲区,并将其内容初始化为指定的字符串内容 str,字符串缓冲区的初始容量为 16 加上字符串 str 的长度。

2.2 案例

理解如下案例即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class StringBuilderTest {
public static void main(String[] args){
// 定义一个空的字符串缓冲区,含有16个字符的容量
StringBuilder str1 = new StringBuilder();
// 定义一个含有10个字符容量的字符串缓冲区
StringBuilder str2 = new StringBuilder(10);
// 定义一个含有(16+4)的字符串缓冲区,"青春无悔"为4个字符
StringBuilder str3 = new StringBuilder("青春无悔");
/*
*输出字符串的容量大小
*capacity()方法返回字符串的容量大小
*/
System.out.println(str1.capacity()); // 输出 16
System.out.println(str2.capacity()); // 输出 10
System.out.println(str3.capacity()); // 输出 20
}
}

3、String和StringBuilder的相互转换

直接看案例

1
2
3
4
5
6
7
8
9
10
11
12
13
public class StringBuilderTest {
public static void main(String[] args){
String s = "abc"; //String转StringBuilder
StringBuilder s1= new StringBuilder(s);
System.out.println(s1); //abc

StringBuilder str=new StringBuilder("javaee");
String str1=str.toString(); //StringBuffer转String(toString方法)
System.out.println(str1); //javaee
System.out.println(s1.getClass()); //class java.lang.StringBuilder
System.out.println(str1.getClass()); //class java.lang.String
}
}

注:可用getClass()方法判断变量类型。

4、StringBuilder类常用方法

常用的有append、delete、insert、replace、reverse、toString、setCharAt(修改指定位置index处的字符)等方法,其他方法和String类似,可自行对照来看。直接看懂以下案例即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class StringBuilderDemo1 {
public static void main(String[] args){
StringBuilder s=new StringBuilder("zhang san 2023");
s.append(" hello"); //zhang san 2023 hello
System.out.println(s);
s.insert(6,"xiao ");
System.out.println(s); //zhang xiao san 2023 hello
s.replace(6,10,"da");
System.out.println(s); //zhang da san 2023 hello
s.delete(6,9);
System.out.println(s); //zhang san 2023 hello
s.reverse();
System.out.println(s); //olleh 3202 nas gnahz
s.setCharAt(4,'H');
System.out.println(s); //olleH 3202 nas gnahz
String str=s.toString(); //StringBuilder 转 String
System.out.println(str); //olleH 3202 nas gnahz
System.out.println(s.getClass()); //判断变量s的类型,class java.lang.StringBuilder
System.out.println(str.getClass()); //判断变量str的类型,class java.lang.String
System.out.println(s.length()); //20
}
}

通过以上可以看出,StringBuilder和StringBuffer功能很相似,在对象创建和常用方法上基本都相同,所以在学习和记忆时侧重记住二者不同的地方即可。

5、String/StringBuffer/StringBuilder小结

总结一下三者之间的一些联系与区别。

5.1 背景及功能重述

1)String

String 是 Java 中基础且重要的类,被声明为 final class,是==不可变字符串==。因为它的不可变性,所以拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。

2)StringBuffer

StringBuffer 就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类。它提供了 append 和 add 方法,可以将字符串添加到已有序列的末尾或指定位置,它的本质是一个==线程安全的可修改==的字符序列。

3)StringBuilder

很多情况下字符串拼接操作不需要线程安全。StringBuilder 是 JDK1.5 发布的,它和 StringBuffer 本质上没什么区别,就是==去掉了保证线程安全的那部分,减少了开销==。

5.2 线程安全

StringBuffer:线程安全

StringBuilder:线程不安全

5.3 速度

一般情况下,速度==从快到慢为 StringBuilder > StringBuffer > String==

从效率和性能角度出发,如果==不考虑线程安全的话,优先推荐使用StringBuilder==

5.4 使用环境

操作少量的数据使用 String。

单线程操作大量数据使用 StringBuilder。

多线程操作大量数据使用 StringBuffer。

三、StringJoiner类

1、概述

StringJoiner是Java8新出的一个类,作用是在构造字符串时可以自动添加前缀、后缀及分隔符,无需实现添加字符的逻辑。StringJoiner是通过StringBuilder进行封装实现的,性能和StringBuilder差不多,也是==非线程安全==的。

方法选择:简单的字符串拼接,直接使用”+”。for循环中进行字符串拼接,考虑StringBuilder和StringBuffer。通过一个List进行字符串拼接,考虑StringJoiner。方法不固定,根据情况自由选择。

2、StringJoiner构造方法

1)两种如下

1
StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix)  //分隔符,前缀,后缀
1
StringJoiner(CharSequence delimiter)    //只有分隔符

2)案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//前后缀拼接
import java.util.StringJoiner; //必须先导包才能用
public class StringJoinerDemo {
public static void main(String[] args) {
String[] names={"zhangsan","lishi","wangwu"};
StringJoiner sj=new StringJoiner(", "); //只有分隔符的构造方法
StringJoiner sj1=new StringJoiner(", ","[","]"); //含分隔符,前缀,后缀的构造方法

StringJoiner sj2 = new StringJoiner("\", \"", "[\"", "\"]"); //转义,显示""
for(String name:names){
sj.add(name);
sj1.add(name);
sj2.add(name);
}
System.out.println(sj); // zhangsan, lishi, wangwu
System.out.println(sj1); // [zhangsan, lishi, wangwu]
System.out.println(sj2); // ["zhangsan", "lishi", "wangwu"]
}
}
1
2
3
4
5
6
7
8
9
10
11
//字符串拼接
import java.util.StringJoiner;
public class StringJoinerDemo1 {
public static void main(String[] args){
StringJoiner sj=new StringJoiner(" ","[","]");
sj.add("Hello");
sj.add("Java");
sj.add("SE");
System.out.println(sj); // [Hello Java SE]
}
}

在不需要指定“开头”和“结尾”的时候,用String.join()更方便,如下

1
2
3
4
5
6
7
8
9
public class StringJoinerDemo1 {
public static void main(String[] args){
String[] names = {"Bob", "Alice", "Grace"};
String join = String.join(". ", names);
System.out.println(join); // Bob. Alice. Grace
String str = String.join(", ", "hello", "world", "测试", "继续加", "无限加");
System.out.println(str); // hello, world, 测试, 继续加, 无限加
}
}